// Compute pattern angle of a vector on the sky
double procedure AngleFromVector {
    {double,double} vector = {1.0,1.0}; // Vector
}{
    double degpi = 180.0 / 3.14159265;
    double fullcircle = 360.0;
    double angle = atan2(vector{0},vector{1}) * degpi;
    // translate into range between 0 and 360 degrees
    angle = (angle + fullcircle) % fullcircle;

    return angle;
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the OTF observing mode
procedure OTFmap_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int nlines_tot = 1; // Total number of lines to scan
    int n_linesperscan = 1; // Number of lines between two OFFs
    int n_intoff = 3; // Number of data dumps for the OFF integration time
    int n_pp = 10; // Number of data dumps per line
    int n_loadinterval = 1; // number of nods before a load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,2,2,40,10,20,21,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int toffslew = telescopetimes[6];
    // slew dead time between points
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // Count OFFs by hand, their counter is not returned in the state array
    int ioff = 0;
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
        }
        if(state[0] == 4) {
            // OFF Integration
            HIFIConfigureContIntegration(data_time,n_intoff,band,lo_freq,backendreadoutparms);
            HIFIContOffIntegration(data_time,n_intoff,rates);
            // OFF counter
            ioff = ioff + 1;
            // Check for normal slew after OFF
            if(state[2] * state[3] < nlines_tot) {
                HIFIActiveHK("normal",toffslew);
            }
        }
        if(state[0] == 8) {
            // OTF integration
            // Check whether we come from the OFF
            if((state[2] + n_linesperscan - 1) % n_linesperscan == 0) {
                HIFIConfigureContIntegration(data_time,n_pp,band,lo_freq,backendreadoutparms);
            }
            HIFIContOnIntegration(data_time,n_pp,rates);
            // Check for normal slew towards the OFF
            if(state[2] % n_linesperscan == 0) {
                if(ioff % n_loadinterval > 0) {
                    HIFIActiveHK("normal",toffslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load slew
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
        }
        if(state[0] == 5) {
            // Final hold - close observation
            delay(readoutdead);
            HIFICloseObs();
        }
    }
}

//////////////////////////////////////////////////////////////////
// Procedure to compute detailed pre timing for the version of the
// frequency switch mode with baseline measurement
// 
{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} procedure FSwitch_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_chop_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int n_chop_off = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF calibration cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed  
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq + min(freq_throw,0.0),lo_freq + max(freq_throw,0.0));
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    CheckDataTaking(backendreadoutparms,data_time_off);
    CheckFswOutOfBand(band,lo_freq,freq_throw,backendreadoutparms);
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    // Compute parameters for the instrument timing
    int on_inttime = 2 * n_chop_on * data_time;
    int off_inttime = 2 * n_chop_off * data_time_off;
    // compute load integration time
    int loadlength = duration(DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // For double phases I can use the added jitterdead in both phases for load
    int halfloadlength = (loadlength - jitterdead + 1) / 2;
    // Compare load interval and position switch interval
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    int n_load_on = on_inttime / load_spacing;
    int n_load_off = off_inttime / load_spacing;
    // This determines the order of the loops
    if(load_spacing > 2 * on_inttime) {
        int n_per_on = n_chop_on;
        bool end_load_on = false;
        int on_pointing = on_inttime + jitterdead;
    } else {
        n_per_on = n_chop_on / (n_load_on + 1);
        if(n_per_on < 1) {
            SError("FS phase length on source too long relative to load period.");
        }
        end_load_on = true;
        on_inttime = 2 * n_per_on * (n_load_on + 1) * data_time;
        on_pointing = on_inttime + halfloadlength + n_load_on * loadlength + jitterdead;
    }
    if(load_spacing > 2 * off_inttime) {
        int n_per_off = n_chop_off;
        bool end_load_off = false;
        int off_pointing = off_inttime + jitterdead;
    } else {
        n_per_off = n_chop_off / (n_load_off + 1);
        if(n_per_off < 1) {
            SError("FS phase length on OFF position too long relative to load period.");
        }
        end_load_off = true;
        off_inttime = 2 * n_per_off * (n_load_off + 1) * data_time_off;
        off_pointing = off_inttime + halfloadlength + n_load_off * loadlength + jitterdead;
    }
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFIFsw(band,lo_freq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,true);
    }
    initlength = initlength + loadlength;
    // Compute the overall cycle length
    // First estimate of the load interval
    int n_loadinterval = imax(load_interval / (on_pointing + off_pointing),1);
    // Exception handling for very uneven phases
    if(end_load_on || end_load_off) {
        n_loadinterval = 1;
    }
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed for telescope call and post_timing processing

    return {on_inttime,off_inttime,on_pointing,off_pointing,loadlength,jitterdead,load_spacing,n_loadinterval,n_per_on,n_per_off,n_load_on,n_load_off,end_load_on,end_load_off,initlength,dangling};
}

// HBB Response time, procedure
procedure HBB_Response_time_proc_fm {
}{
    error("Cannot be used in warm context");
    //
    //It just configures the FPU, setting the HBB at the required temp.
    //Then we just wait for the temperature to stabilize to the final value...
    //For the sake of simplicity, we use Band0 parameters.
    Band0_hbb_on_fm("0","CLOSE");
    //
}

//Set LCU back to standby status without setting any particular LO band, block
//LCU is only set to standby if the band has been switched off
block LCU_standby_block_aot HIFI 6629 {
}{
    {double,string}[] result = ConfigurationReader("name_delays",["stdby_delay"],"0",0.0);
    int stdby_delay = iround(result[0]{0});
    //
    //Set in standby mode
    Hifi_HIFI_HL_Standby($BBID);
    delay(stdby_delay);
}

//Heater setting in manual commanding
mode HifiManCmd_Set_HL_Heater {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    mois_comment("Procedure for LOU heater setting adjustement");
    StartMode_block_ops();
    //
    mois_step("Set heater voltage");
    mois_spacon("In the next TC, the heater voltage HP397194 should be treated as an FP");
    HL_heater_block_fm("1a","nominal");
    //
    StopMode_block_ops();
    // -> to issue last obsd/bbid
}

// IV curve, block
block IVcurve_pumped_fm HIFI 3213 {
    string band = "1a";
    double lo_freq = 522.0; //LO frequency
}{
    //Start_block() ;   
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["bias_min_h","bias_max_h","bias_steps_h","bias_min_v","bias_max_v","bias_steps_v"],band,0.0);
    //H polar
    double bias_min_h = result_d[0]{0};
    double bias_max_h = result_d[1]{0};
    int steps_h = iround(result_d[2]{0});
    //V polar
    double bias_min_v = result_d[3]{0};
    double bias_max_v = result_d[4]{0};
    int steps_v = iround(result_d[5]{0});
    //Nominal bias set at the end
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_h = result_d[0]{0};
    double bias_v = result_d[1]{0};
    double magnetcurrent_h = 0.0;
    double magnetcurrent_v = 0.0;
    //
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        magnetcurrent_h = result_d[0]{0};
        magnetcurrent_v = result_d[1]{0};
    }
    // 
    //The IVCurve is done on the smallest range and the finest step
    double bias_min = max(bias_min_h,bias_min_v);
    double bias_max = min(bias_max_h,bias_max_v);
    int steps = iround(max(double(steps_h),double(steps_v)));
    //
    //First set magnets to max.
    double magnet_current_max_h = 0.0;
    double magnet_current_max_v = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
        magnet_current_max_h = result_d[0]{0};
        magnet_current_max_v = result_d[1]{0};
    }
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_current_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_current_max_v);
    delay(1);
    //Perform IV curve
    IVcurve(band,bias_min,bias_max,steps,magnetcurrent_h,magnetcurrent_v,bias_h,bias_v);
}

//Notify PDU status OFF, procedure
procedure HIFI_notify_PDU_status_off_proc_ops {
    string status_FCU = "OFF" in ["ON","OFF"]; //Status of FCU
    string status_LCU = "OFF" in ["ON","OFF"]; //Status of LCU
    string status_WBSV = "OFF" in ["ON","OFF"]; //Status of WBSV
    string status_WBSH = "OFF" in ["ON","OFF"]; //Status of WBSH
    string status_HRSV = "OFF" in ["ON","OFF"]; //Status of HRSV
    string status_HRSH = "OFF" in ["ON","OFF"]; //Status of HRSH
}{
    Hifi_HIFI_notify_PDU_status(status_FCU,status_LCU,status_WBSV,status_WBSH,status_HRSV,status_HRSH);
    //Prepare message for operator: we will check whether one particular HK is ON
    if(status_FCU == "OFF") {
        string subsyst_off = "HI_FCU_S";
    }
    if(status_WBSH == "OFF") {
        subsyst_off = "HI_WBSH_S";
    }
    if(status_WBSV == "OFF") {
        subsyst_off = "HI_WBSV_S";
    }
    if(status_HRSH == "OFF") {
        subsyst_off = "HI_HRSH_S";
    }
    if(status_HRSV == "OFF") {
        subsyst_off = "HI_HRSV_S";
    }
    if(status_LCU == "OFF") {
        subsyst_off = "HI_LCU_S";
    }
    mois_tmcheck("Check that the HK parameter " + subsyst_off + " is OFF.");
    delay(1);
}

//Peak test configuration, block
block Peakup_test_configure_block_fm HIFI 3820 {
    string band = "1" in ["1","2","3","4","5","6","7"]; // HIFI band
    string mixer_polarization = "H" in ["H","V"]; //mixer polarization to be used 
}{
    //Start_block();
    //Get offset of observed aperture wrt band 6H
    string tab = "peakup_offset.config";
    double peakup_scale_y = dlookup(tab,"" + band,"scale_y");
    double peakup_scale_z = dlookup(tab,"" + band,"scale_z");
    double offset_y = dlookup(tab,"" + band,"offset_y_H");
    double offset_z = dlookup(tab,"" + band,"offset_z_H");
    if(mixer_polarization == "V") {
        offset_y = dlookup(tab,"" + band,"offset_y_V");
        offset_z = dlookup(tab,"" + band,"offset_z_V");
    }
    //
    Hifi_HIFI_configure_peakup_r1($BBID,iround(peakup_scale_y),iround(peakup_scale_z),iround(offset_y),iround(offset_z));
    //no delay ? tests with fm_cus_12.7 show that 1sec may be not enough
    delay(2);
}

// common statistics messages
procedure PerformanceMessages {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int totaltime = 180; // HIFI time without initial slew
    double posinttime = 10.0; // Integration time on source
    double posofftime = 10.0; // Integration time on OFF
    double timeefficiency = 0.5; // time efficiency
    double noiseefficiency = 0.125; // noise efficiency
    double relnoise = 0.01; // drift noise contribution
    bool reduced = false; // whether deconvolution is assumed
}{
    // close any previous messages
    message("</p>");
    message("<h2>Observing mode performance</h2>");
    message("<p>");
    // Actual messages
    message("Observing time without initial slew " + totaltime + "s<br>");
    message("On-source integration time " + posinttime + "s<br>", 1);
    message("OFF integration time " + posofftime + "s<br>", 1);
    message("Overhead " + (double(totaltime) - posinttime - posofftime) + "s<br>", 1);
    message("</p><p>");
    message("Total time efficiency " + timeefficiency * 100.0 + "%<br>", 1);
    message("Total noise efficiency " + noiseefficiency * 100.0 + "%<br>", 1);
    message("Drift noise contribution " + relnoise * 100.0 + "%<br>", 2);
    message("</p>");
    // Auxiliary explanations - Main beam
    double fwhm = GetMainBeamSize(band,lo_freq);
    fwhm = fwhm * 3600.0;
    double eta_mb = InterpolateCoupling(band,lo_freq);
    // System temperature is recomputed to be printed without passing
    double tsys = InterpolateTsys(band,lo_freq);
    double[] gssb = InterpolateGssb(band,lo_freq);
    double tsys_lsb = tsys / (eta_mb * gssb[0]);
    double tsys_usb = tsys / (eta_mb * gssb[1]);
    message("<p>");
    message("The system noise temperature at " + lo_freq / 1000.0 + " GHz is " + tsys_lsb + " K in the lower and " + tsys_usb + " K in the upper sideband.", 0);
    message("<br><strong>");
    if(reduced) {
        message("Deconvolved noise values are given on a two-polarization," + " single-sideband, main beam temperature scale of a " + fwhm + "'' beam with a main beam efficiency of " + eta_mb * 100.0 + "%.", 1);
    } else {
        message("All noise values are given on a two-polarization," + " single-sideband, main beam temperature scale of a " + fwhm + "'' beam with a main beam efficiency of " + eta_mb * 100.0 + "%.", 1);
    }
    message("</strong></p>");
    message("</body></html>");
}

// Second part of FPSS FM functional test, block
// Check cryogenic health
block FT_FPU_check_cryohealth_fm HIFI 3801 {
    string band = "1a";
    int integ_time = 4; //Integation time in seconds
    double lo_freq = 500.0; //LO frequency
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //We will check the IF noise
    // Backends are required !!
    //We assume the bias voltage is already at its 
    //normal value
    //Get magnets in case band 1-5 is used
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        {double,string}[] result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
        //
        //Set magnet to max. for hysteresis issues
        Hifi_HIFI_CH1_MX_MG_C($BBID,result[0]{0});
        Hifi_HIFI_CV1_MX_MG_C($BBID,result[1]{0});
        delay(1);
    }
    //Get nominal biases and magnets
    result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v","norm_magn_h","norm_magn_v"],band,lo_freq);
    double bias_h = result[0]{0};
    double bias_v = result[1]{0};
    double magnet_current_h = result[2]{0};
    double magnet_current_v = result[3]{0};
    //
    Hifi_HIFI_FCU_parameter_scan($BBID,1,1,0.1,bias_h,bias_v,0.0,magnet_current_h,magnet_current_v,0.0);
    //Sets magnet current
    delay(2);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //
    //Perform IF noise test
    result = ConfigurationReader("name_confilfpu",["bias_low_resistive_h","bias_low_resistive_v","bias_high_resistive_h","bias_high_resistive_v"],band,0.0);
    //1. bias 5 Volts
    bias_h = result[0]{0};
    bias_v = result[1]{0};
    //
    Hifi_HIFI_FCU_parameter_scan($BBID,1,1,0.1,bias_h,bias_v,0.0,0.0,0.0,0.0);
    //Sets magnet current to 0
    delay(2);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //
    //Perform IF noise test
    //2. bias 10 Volts
    bias_h = result[2]{0};
    bias_v = result[3]{0};
    //
    Hifi_HIFI_FCU_parameter_scan($BBID,1,1,0.1,bias_h,bias_v,0.0,0.0,0.0,0.0);
    //Sets magnet current to 0
    delay(2);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //
}

//HIFI measurement of HEB spectra variation vs Imix, mode
//Takes spectra over the full Vd2 range
obs HifiEng_HEB_Spectra_vs_Imix_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    bool lo_chain_switch = false; //Whether the chain is already switched on
    int testtime = 900; //total time we want to spend on testing
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(HEB_Spectra_vs_Imix_proc_fm_COP(band,lo_chain_switch,testtime));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            HEB_Spectra_vs_Imix_proc_fm_COP(band,lo_chain_switch,testtime);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//Systematic deflux after LO switch-on, procedure
procedure Deflux_at_switchon_proc_aot {
    string band = "4a" in ["ALL","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band. ALL does all bands and all multipliers
}{
    //
}

// Integrate only on external cold, block
// We take 1 spectrum per phase.
block Stability_extcold_fm HIFI 3437 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integrations
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string obsmode = "fastchop" in ["fastchop","tp"]; //tp or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    Start_block();
    Chopper_Rotation_proc_fm(band,"chop_hot_ang","chop_M3_ang");
    //Look at M3
    //Get chopper settings
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_M3"],band,0.0);
    double chop_M3 = result[0]{0};
    //Close shutter
    //Shutter_rotate_proc_fm("closed");
    //Do a long integration
    //	- for B1-5, use 2 sec. with wbs or hrs only, thus tp is OK
    //  - for B6: use 1 sec. with reduced wbs (wbsFast), thus tp is OK
    //We implement a special spectroscopy configuration with fixed values
    if(obsmode == "tp") {
        Total_power_spectro_for_Stability_proc_fm(band,n,integ_time,backend,hrs_mode);
    }
    if(obsmode == "fastchop") {
        Fast_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_M3,chop_M3,chop_phase);
    }
}

//DEPRECATED. USE OBS COMMAND INSTEAD
// WBS zero, procedure
// This is a work-around for WBS_Zero.
//procedure WBS0_fm_proc {
//  string band="1a";	     // HIFI band
//  }{
//    Hifi_HIFI_Single_cmd ($BBID, "HWH_ZERO_ON"); 
//    Hifi_HIFI_Single_cmd ($BBID, "HWV_ZERO_ON"); 
//    delay (1) ;
//    //Configure spectroscopy
//    {double, string}[] result_d = ConfigurationReader("name_delays",
//	["integ_time_zero"],band,0.0);
//    int integ_time_zero = iround(result_d[0]{0});
//    Configure_Spectrometer_proc_fm(band,integ_time_zero,["wb1","wb1"],backend);
//    //
//    HIFI_Spectr_total_power_proc_fm(band,"wbs",integ_time_zero);
//    //
//    Hifi_HIFI_Single_cmd ($BBID, "HWH_ZERO_OFF"); 
//    Hifi_HIFI_Single_cmd ($BBID, "HWV_ZERO_OFF"); 
//    delay (1) ;
//    //
//  }
//////////////////////////////////////
// WITH THE NEW RULES THIS SHOULD BE
// A BLOCK. HOWEVER THIS PROCEDURE SHOULD
// NOT BE USED AS DEFAULT SO I EXPECT IT
// DISAPPEARS SOON.
//////////////////////////////////////
// WBS comb, procedure
// This is a work-around for WBS_Comb, with controlable att.
// and no zero integration
// The integration time is read in a configuration file
procedure WBS_comb_fm_proc {
    string band = "1a"; // HIFI band
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Set zero On
    Hifi_HIFI_switch_zero_WBS_H($BBID,"ON");
    Hifi_HIFI_switch_zero_WBS_V($BBID,"ON");
    delay(1);
    //We have to set attenuators to values different from max.
    //Initial configuration
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4_comb","hwh_att_band3_comb","hwh_att_band2_comb","hwh_att_band1_comb","hwh_att_in_comb"],band,0.0);
    string hwh_laser1_s = result_d[0]{1};
    string hwh_laser2_s = result_d[1]{1};
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = iround(result_d[4]{0});
    int hwh_att_band3 = iround(result_d[5]{0});
    int hwh_att_band2 = iround(result_d[6]{0});
    int hwh_att_band1 = iround(result_d[7]{0});
    int hwh_att_in = iround(result_d[8]{0});
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4_comb","hwv_att_band3_comb","hwv_att_band2_comb","hwv_att_band1_comb","hwv_att_in_comb"],band,0.0);
    string hwv_laser1_s = result_d[0]{1};
    string hwv_laser2_s = result_d[1]{1};
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = iround(result_d[4]{0});
    int hwv_att_band3 = iround(result_d[5]{0});
    int hwv_att_band2 = iround(result_d[6]{0});
    int hwv_att_band1 = iround(result_d[7]{0});
    int hwv_att_in = iround(result_d[8]{0});
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Configure spectroscopy
    result_d = ConfigurationReader("name_delays",["integ_time_comb"],band,0.0);
    int integ_time_comb = iround(result_d[0]{0});
    Configure_Spectrometer_proc_fm(band,integ_time_comb,["wb1","wb1"],"wbs");
    //
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_ON");
    delay(1);
    //
    HIFI_Spectr_total_power_proc_fm(band,"wbs",integ_time_comb);
    //
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_OFF");
    delay(1);
    Hifi_HIFI_switch_zero_WBS_H($BBID,"OFF");
    Hifi_HIFI_switch_zero_WBS_V($BBID,"OFF");
    delay(1);
    //
    //Set attenuators back to default
    WBS_config_block_fm(band);
}

/////////////////////////////////////////////////////////////////
// Second step of timing computation after telescope behaviour
// is known -  Spectral Scan DBS observing mode
// 
{int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},double,double,double} procedure SScanDBS_post_timing {
    {int,int,int,int,int,int,int,int,int,bool,int,int,int} pre_timing = {4,15,4,21,11,1800,22,32,1,false,0,50,0}; // pre_timing parameter list
    int[] telescopetimes = [300,180,20,1,21,0];
    int grouplen = 1;
    int groupnumber = 50; // Total umber of frequency groups
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    bool fastchop = false; // whether fast-chop is used instead of slow-chop
}{
    // Get all values from the pre_timing section
    int inttime = pre_timing{0};
    int pointing = pre_timing{1};
    int readouttime = pre_timing{2};
    int loadlength = pre_timing{3};
    int jitterdead = pre_timing{4};
    int load_spacing = pre_timing{5};
    int bigtunestep = pre_timing{6};
    int n_loadinterval = pre_timing{7};
    int n_bchop = pre_timing{8};
    bool end_load = pre_timing{9};
    int smallstep = pre_timing{10};
    int initlength = pre_timing{11};
    int dangling = pre_timing{12};
    // Computation for slow-chop or fast-chop
    if(fastchop) {
        int readoutperchop = 1;
    } else {
        readoutperchop = 2;
    }
    // Get all values from the telescope section
    int telinit = telescopetimes[1];
    // Initial slew time
    int slewtime = telescopetimes[2];
    // Slew time to OFF
    int longslew = telescopetimes[4];
    // Actual slew time for load slew
    int pointwaittime = telescopetimes[3];
    // Idle time between two phases
    int tend = telescopetimes[5];
    // Final deceleration time
    //////////////////////////////////////////////////////////////////
    // Now we start the actual computations
    // Pointwaittime is used for tuning
    // In all non-tuning cycles, pointwaittime acts like a longer slew
    slewtime = slewtime + pointwaittime;
    longslew = longslew + pointwaittime;
    // Half tune step has to be rounded up
    int halftunestep = (bigtunestep - jitterdead - pointwaittime + 1) / 2;
    //////////////////////////////////////////////////////////////////////
    // Compute timing parameters for the two cases divided by n_cycles > 1
    //
    // Observations with ncycles >1 may be somewhat less efficient 
    //
    if(n_cycles > 1) {
        int scan_time = 2 * inttime + slewtime;
        // How often do I have to perform a load slew
        // Never switch between short load and long load here
        if(n_loadinterval > 1) {
            int old_n_loadinterval = n_loadinterval;
            n_loadinterval = imax((load_spacing + slewtime) / scan_time,1);
            // fit with n_cycles
            n_loadinterval = imin(n_loadinterval,n_cycles);
            n_loadinterval = IMultiple(n_loadinterval,n_cycles);
            if(n_loadinterval <= 1) {
                n_loadinterval = old_n_loadinterval;
            }
        }
        // part of integrations is removed for tuning
        int n_add = iceil(double(halftunestep) / double(readoutperchop * readouttime));
        n_bchop = n_bchop - n_add;
        if(n_bchop <= 0) {
            SError("Readout cycle too long relative to nod cycle.");
        }
        // Pointing time
        pointing = inttime + jitterdead;
        // Average times for noise estimate
        int shortint = n_bchop * readoutperchop * readouttime;
        double effinttime = double((n_cycles - 1) * inttime + shortint) / double(n_cycles);
        int loadpercycle = n_cycles / n_loadinterval;
        double cycletime = double(2 * pointing) + double(loadpercycle * longslew + (n_cycles - loadpercycle) * slewtime) / double(n_cycles);
        double avchopnum = double(n_cycles * (n_bchop + n_add) - n_add) / double(n_cycles);
        // Compute total duration
        int totaltime = iround(cycletime * double(groupnumber * n_cycles));
    } else {
        // Retuning after each nod cycle
        // Check group length limited by load_interval
        scan_time = 2 * (grouplen * inttime + (grouplen - 1) * smallstep) + bigtunestep + slewtime;
        if(scan_time > load_spacing + slewtime && grouplen > 1) {
            SError("Frequency group length too large for load interval.");
        }
        pointing = grouplen * inttime + (grouplen - 1) * smallstep + halftunestep + jitterdead;
        // Average times for noise estimate
        effinttime = double(grouplen * inttime);
        // ignore the tuning time between cycles
        cycletime = double(longslew + 2 * pointing - bigtunestep);
        avchopnum = double(n_bchop);
        // Compute total duration
        totaltime = (iround(cycletime) + bigtunestep) * groupnumber;
    }
    double tdead = cycletime - 2.0 * effinttime;
    //////////////////////////////////////////////////////////////////////
    // The initial time is no longer contained in the total time
    initlength = initlength - halftunestep;
    int shiftlength = halftunestep;
    // Compute total duration, remove pointwaittime for last slew
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    totaltime = totaltime + dangling - pointwaittime + tend;
    // show gyro-propagation messages
    int pointcycle = longslew + 2 * pointing;
    GCPMessages(pointing,2 * pointcycle,tend);
    // Return all the times needed in the observing mode modules

    return {totaltime,{inttime,pointing,readouttime,loadlength,jitterdead,load_spacing,bigtunestep,n_loadinterval,n_bchop,end_load,shiftlength,initlength,dangling},avchopnum,cycletime,tdead};
}

//HIFI LO tuning only for M1/M2 investigation in 3b, block
//Target current is read from look-up table
block LO_tuning_w_M1M2M3_block_fm HIFI 3919 {
    string band = "3b" in ["3b","3b"]; // HIFI band
    double lo_freq = 930.0; //LO frequency
    double m1 = 10.0; //M1 multiplier voltage
    double m2 = -8.0; //M2 multiplier voltage
    double m3 = 1.5; //M3 multiplier voltage
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    string mixer_polarization = result[0]{1};
    //
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = m1;
    //result[1]{0};
    double m2_v = m2;
    //result[2]{0};
    double m3_v = m3;
    //result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double middle_d2 = result[0]{0};
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * middle_d2;
    //drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    if(band == "3b") {
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum);
        //Send command: specific to M3 in 3b
        delay(config_lo_delay);
        //
        //Additional read of TM pages
        LCU_Read_TM_pages_proc_fm();
    }
    //
    //
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

/////////////////////////////////////////////////////////////////
// Fast chop dual beam switch observing mode
//
// Implemented as procedure returning time and noise levels for HSPOT
{string,double,double}[] procedure HifiPointProcFastDBSSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get the drift parameters to compute the drift noise
    {double,double} phaselengths = DBSPhaseLengths(band,lo_freq,effResolution,continuumDetection,oneGHzReference);
    // Compute derived quantities
    // Top down approach here
    int main_phase = iceil(phaselengths{0});
    int data_time_guess = 40;
    int n_switch_on_guess = main_phase / data_time_guess;
    if(n_switch_on_guess < 2) {
        n_switch_on_guess = 2;
        data_time_guess = main_phase / n_switch_on_guess;
    }
    // Check with data rate
    {int,double[]} dataparms = DataTaking(backendreadoutparms,8);
    int datalimit = 2 * dataparms{0};
    if(data_time_guess < datalimit) {
        data_time_guess = datalimit;
        n_switch_on_guess = 1;
    }
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // Chop phase length
    double phase_min = min(max(phaselengths{1},0.15),1.5);
    int n_int_on_guess = ifloor(double(data_time_guess) / (2.0 * phase_min));
    int n_int_on_range = -n_int_on_guess / 2;
    if(n_int_on_range == 0) {
        n_int_on_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_int_on",double(n_int_on_guess),double(n_int_on_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)}];

    return retvalues;
}

// FSW Response time, procedure
procedure FSW_Response_time_proc_fm {
    double hr_central_freq = 5.0; //IF freq of HRS hr sub-band in GHz
    string hrs_polar = "H" in ["H","V","B"]; //HRS polarizations in use
    int[] del_wbs_param = [10,200,10,100]; //starting, ending and step value for del_wbs
}{
    //FSW will be called with increasing delta time between the two phases
    //Need special spectroscopy configuration:
    //	- HRS only in hr resolution, optionally H, V or B, 1sec integration
    HRS_config_resol_block_fm("0",["hr","hr"]);
    FSW_Response_time_HRSConfig_block_fm("0",["hr","hr"],hr_central_freq);
    //Optimize HRS level
    HRS_tune_block_fm("0");
    //Now call FSW at successive del_wbs
    FSW_Response_time_block_fm(hrs_polar,del_wbs_param);
    //
}

// Chopper scan, procedure (IF power as function of chopper position)
procedure Chopper_scan_proc {
    string band = "1a"; // HIFI band		//Setting file
    double chopper_pos_min = -7.0; //minimum chopper position
    double chopper_pos_max = 8.0; //maximum chopper position
    int n_steps = 300; //number of steps
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3
    string shutter = "open"; //Status of shutter during scan: closed/open
    int integ_time = 4; //Total integration time in sec.: at least 2sec !  
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "tp" in ["tp","slowchop","fastchop"]; //modulation mode between hot/cold: tp, slowchop, fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
    bool ref_position = false; //Do we take a reference spectrum every 100sec ?
    bool shutter_used = true;
}{
    double chop = 0.0;
    //
    //close shutter if necessary
    if(shutter_used) {
        //Shutter_rotate_proc_fm("closed");
    }
    //
    //Prepare for backend attenuation on hottest spot
    if(shutter == "open") {
        //External hot is available
        Chopper_Rotation_block_fm(band,"chop_hot_ang","chop_M3_ang");
    } else {
        //Have to use internal hot
        Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    }
    //
    //Configure and tune backends
    //16/11/05: NOT ANYMORE, THIS SHOULD BE DONE INDEPENDENTLY
    //HRS_config_block_fm(band,hrs_mode);
    //WBS_config_block_fm(band);
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration after tuning
    int[] res = [0,0];
    int n_wbs1 = 0;
    int n_hrs_trans = 0;
    int total_time = 0;
    if(chopmode == "tp") {
        res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
        total_time = res[0] * res[1];
    }
    if(chopmode == "slowchop") {
        res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
        total_time = res[0] * res[1];
    }
    if(chopmode == "fastchop") {
        //Integ_time expected here is the TOTAL integration time with both phases + residual HRS time
        res = Configure_Spectrometer_fast_chop_proc_fm(band,integ_time * 2,chop_phase,hrs_mode,backend);
        total_time = iceil(chop_phase * double(res[1] * res[2]));
        n_wbs1 = res[2];
        n_hrs_trans = res[3];
        //debug_print("Fast chop parameters: n_wbs1 = "+res[2]+", n_hrs_trans = "+res[3]);
    }
    //
    Chopper_scan_fm(band,chopper_pos_min,chopper_pos_max,n_steps,total_time,backend,chopmode,n_wbs1,n_hrs_trans,ref_position,shutter_used,hrs_mode,chop_phase);
    //
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //We end with a spectrum on both external loads: Only for ILT !!
    //They are needed in the analysis
    //Hot_cold_external (band,total_time,backend);	//integration on external loads: sky path
    //
}

//////////////////////////////////////
// low-level procedures
//////////////////////////////////////
string procedure GetLcuSection {
}{
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant"],"0",0.0);
    string section = "P";
    if(result_d[0]{1} == "redundant") {
        section = "R";
    }

    return section;
}

procedure HalfFastDBSRaster_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 10 in [4,80]; // data dump interval
    int n_int = 20; // number chop cycles to integrate in ICU before transfer
    int n_seq = 1; // number of data transfer cycles per pointing
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF cycles 
    int n_pointsperscan = 1; // Number of points measured before moving to the second pointing phase
    int n_loadinterval = 10; // number of nods before a load measurement
    int n_load = 0; // additional load measurements in one pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,10,0,10,20,21,0,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    bool iscross = false; // Whether we use a cross instead of a raster
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Fixed timings in the fast-chop mode
    int load_datatime = GetStdLoadReadout(band,lo_freq);
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time / 2);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,true);
    int readoutdead = FastChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // There is no nod counter in the return values - count this by hand
    int inod = 0;
    // Do I have to make loads in short nods and subsequent holds?
    if(iscross) {
        bool holdforload = n_pointsperscan > 1;
    } else {
        holdforload = n_pointsperscan == 1 && n_loadinterval > n_cycles;
    }
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    int[] choppars = [2 * n_int,0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - hkduration - loadlength);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            runintostate = false;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            // The use of n_load differs by 1 from the other observing modes here
            for(int i1 = 1 .. n_load - 1) {
                HIFIFastHalfChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFIFastHalfChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            // n_pointsperscan=1, n_loadinterval > n_cycles
            if(state[3] % 2 == 1) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
        }
        // Second pointing phase
        if(state[0] == 7) {
            // second nod position
            choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            for(int i2 = 1 .. n_load - 1) {
                HIFIFastHalfChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle 
            HIFIFastHalfChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            if(state[3] % 2 == 0) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
        }
        // Load nod
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            runintostate = false;
        }
        // Hold
        if(state[0] == 6) {
            // finished shift of instrument operations relative to pointing command
            runintostate = false;
        }
        // Final load
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

// Compute the offset between two points
// This is an approximation for small offsets
{double,double} procedure ApproxAngularOffset {
    {double,double} vector1 = {0.0,0.0}; // First vector
    {double,double} vector2 = {0.2,0.2}; // Second vector
}{
    double pideg = 3.14159265 / 180.0;
    double fac = cos(0.5 * pideg * (vector1{1} + vector2{1}));

    return {(vector2{0} - vector1{0}) * fac,vector2{1} - vector1{1}};
}

//  LCU3a configuration into SAFE mode, procedure
procedure LCU3a_config_safe_proc_fm {
    string band = "3a"; // HIFI band
    double lo_freq = 810.0 in [807.0,848.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

//////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the observing mode
{double,double,double,double,double} procedure SScanDBS_noisecomputer {
    string band = "4a"; // HIFI band
    double reffreq = 978300.0; // Reference LO frequency in scan center
    int nfreq = 4; // Number of frequency points per IF
    bool dsb = true; // Both sidebands covered
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuum = false; // Whether timing is for total-power level
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double} tact = {10.0,4.9,0.05}; // Field of actual dead and integration times
}{
    // spectral scans always use the full bandwidth for reference
    bool oneGHzReference = false;
    double tdead = tact{0};
    // Average total dead time in one scan
    double inttimeperphase = tact{1};
    // Actual integration time
    double deadtimeperphase = tact{2};
    // Dead time per switch phase
    // Currently it is not possible to return both drift noise and radiometric
    // noise so that only their sum is computed.
    //
    // Get parameters which are needed
    double tsys = InterpolateTsys(band,reffreq);
    double eta_mb = InterpolateCoupling(band,reffreq);
    double[] gssb = InterpolateGssb(band,reffreq);
    // Get the drift parameters to compute the drift noise
    if(continuum) {
        double[] allanparms = InterpolateTpAllan(band,reffreq,oneGHzReference);
    } else {
        allanparms = InterpolateSpecAllan(band,reffreq,oneGHzReference);
    }
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double allan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // Differential Allan variance
    if(continuum) {
        allanparms = InterpolateTpChopAllan(band,reffreq,oneGHzReference);
    } else {
        allanparms = InterpolateSpecChopAllan(band,reffreq,oneGHzReference);
    }
    // rescale to frequency resolution
    double dalpha = allanparms[1];
    binningexp = 1.0 / allanparms[2];
    double dallan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double dallan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // Compute integration time in one pointing cycle
    double deadtimeperswitch = deadtimeperphase;
    double effinttime = (tscan - tdead) / 2.0;
    // Get actual noise
    // This is returned twice: for both limiting resolutions
    double systemnoise_lores = DoubleDifferenceNoise(inttimeperphase / allan_time_lores,[1.0,1.0,effinttime / allan_time_lores,effinttime / allan_time_lores,deadtimeperswitch / allan_time_lores,tdead / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    double systemnoise_hires = DoubleDifferenceNoise(inttimeperphase / allan_time_hires,[1.0,1.0,effinttime / allan_time_hires,effinttime / allan_time_hires,deadtimeperswitch / allan_time_hires,tdead / allan_time_hires,alpha,dallan_time_hires / allan_time_hires,dalpha]);
    double noiseratio = DoubleDifferenceNoiseRatio(inttimeperphase / allan_time_lores,[1.0,1.0,effinttime / allan_time_lores,effinttime / allan_time_lores,deadtimeperswitch / allan_time_lores,tdead / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    // Compute total double sideband noise
    // Correct for signal in difference phase
    double dsbnoise_lores = systemnoise_lores / (eff_resolution{1} * 4000000.0 * tscan);
    double dsbnoise_hires = systemnoise_hires / (eff_resolution{0} * 4000000.0 * tscan);
    // Divide by n_cycles and number of frequencies
    double accumulation = double(nfreq * n_cycles);
    // Compute noise temperature
    dsbnoise_lores = tsys * sqrt(dsbnoise_lores / accumulation);
    dsbnoise_hires = tsys * sqrt(dsbnoise_hires / accumulation);
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Check for double sideband coverage
    if(dsb) {
        // Combine both sidebands
        // In full spectral scans we have only a combined noise temperature for 
        // both sidebands
        double usbnoise_lores = dsbnoise_lores / sqrt(gssb[0] * gssb[0] + gssb[1] * gssb[1]);
        double usbnoise_hires = dsbnoise_hires / sqrt(gssb[0] * gssb[0] + gssb[1] * gssb[1]);
        double lsbnoise_lores = usbnoise_lores;
        double lsbnoise_hires = usbnoise_hires;
    } else {
        // Get single sideband noise equivalent
        usbnoise_lores = dsbnoise_lores / gssb[0];
        usbnoise_hires = dsbnoise_hires / gssb[0];
        lsbnoise_lores = dsbnoise_lores / gssb[1];
        lsbnoise_hires = dsbnoise_hires / gssb[1];
    }
    // In spectral scans we have only a combined noise temperature for both
    // sidebands, so that the USB/LSB separation is not used

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiseratio};
}

//  LCU5b configuration into SAFE mode, procedure
procedure LCU5b_config_safe_proc_fm {
    string band = "5b"; // HIFI band
    double lo_freq = 1200.0 in [1192.0,1242.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

// Equivalent procedure for configuration parameters following
// the master file structure currently used for these calibration files
//
// This is the generic part used for ILT and AOTs
//
{double,string}[] procedure FlexibleConfigurationReader {
    string mainmasterfile = "configuration_masterfile"; // Configuration master file
    string topicname = "name_confilfpu"; // Name of entry in master file
    string[] objectnames = ["bias_standby_h"]; // Names of calibration objects to be read
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    // first step: read band master file
    string masterfile = slookup(mainmasterfile,band,"filename");
    // read master file
    string calibfile = slookup(masterfile,topicname,"value_string");
    int dep = ilookup(masterfile,topicname,"dependence");
    int readnum = length(objectnames);
    {double,string}[] retvalues = [];
    if(dep == 0) {
        // Quantity is only band dependent
        // directly read from file looking up the object
        for(int k = 1 .. readnum) {
            double dres = dlookup(calibfile,objectnames[k - 1],"value");
            string sres = slookup(calibfile,objectnames[k - 1],"value_string");
            retvalues[k - 1] = {dres,sres};
        }
    } else {
        // Quantity is band and frequency dependent
        // read interpolated value from the data base
        for(int j = 1 .. readnum) {
            dres = interpolate(calibfile,objectnames[j - 1],lo_freq);
            sres = "";
            retvalues[j - 1] = {dres,sres};
        }
    }

    return retvalues;
}

//backend attenuation during peakup in IST context, procedure
procedure Peakup_backend_attenuation_proc_fm {
    string band = "1" in ["1","2","3","4","5","6","7"]; // HIFI band
    int position = 1 in [1,9]; //peakup pattern sequence number: from 1 to 9
    string peakup_matrix = "centred" in ["centred","offseted","flat"]; //Which brightness distribution to simulate with shutter
    string backend = "hrs" in ["hrs","wbs"]; //Backend in use: hrs or wbs
    int total_time = 2; //Total integration time in sec.
}{
    //Get number of shutter rotation steps depending on position number
    string band_nb = band + "a";
    string name_shutter_pos = "name_shutter_pos_centred";
    if(peakup_matrix == "offseted") {
        name_shutter_pos = "name_shutter_pos_offseted";
    }
    {double,string}[] result = ConfigurationReader(name_shutter_pos,["new_att"],band_nb,double(position));
    //If flat distribution is chosen, the attenuators shall not be changed
    double new_att = result[0]{0};
    if(peakup_matrix == "flat") {
        new_att = 10.0;
    }
    //
    //Apply new attenuation
    if(backend == "hrs") {
        HRS_config_att_lo_w_att_fm(band_nb,["wb1","wb1"],new_att);
    } else {
        new_att = new_att + 5.0;
        //for WBS we move the main att, all others to 7
        int[] att_h = [7,7,7,7,iround(new_att)];
        int[] att_v = [7,7,7,7,iround(new_att)];
        //Presently assumes use of laser2
        WBS_config_w_laser_and_att_proc_fm(band_nb,"Laser2","Laser2",att_h,att_v,total_time,backend);
    }
    //
}

//HIFI-COP-3-Deflux
//Systematic deflux at beginning of each OD, or band switch
procedure Deflux_SingleBand_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b"]; // HIFI band. ALL does all mixer bands
}{
    // Get reference frequency
    string keyfreqname = "keyfreq";
    //this is for cold LO operations
    // "keyfreq" for cold LO operations
    // "keyfreq_dummy"  for dummy LO operations
    double[] result_d = CalibrationReader("name_keyfreq",[keyfreqname],band,0.0);
    double lo_freq = result_d[0];
    //
    //Switch on LO
    LCU_switchon_proc_fm(band);
    //Wait 1 min from now
    sync();
    int startobs = time();
    //Insert FPU setting at this frequency
    Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
    delay(60 - (time() - startobs));
    //Tune LO
    LO_tuning_block_fm(band,lo_freq);
    //First magnet tuning
    Magnet_tuning_block_fm(band,lo_freq,"HRS",40);
    //Deflux heaters
    Heater_cop(band);
    //Second magnet tuning
    Magnet_tuning_block_fm(band,lo_freq,"HRS",40);
}

//Find out stepmargin
double procedure Stepmargin {
    double low = 0.0;
    double high = 10.0;
    string parameter = "hifi_HIF_mx_mg_step_C";
}{
    double range = high - low;
    int range_raw = convert_to_raw(parameter,range);
    if(range_raw < 1) {
        range_raw = 1;
    }
    double bitsize = range / double(range_raw);

    return bitsize / 4.0;
}

// Double load chop measurement performed at both frequencies
// of a frequency switch observation
// Most code is dublicated from normal load measurement
//
// Most generic version for spectral scans with potentially different 
// frequencies for tuning and timing and retuning switch
//
procedure SScanDoubleLoadMeasurement {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double tuning_freq = 978200.0; // LO tuning frequency
    double lo_freq = 978200.0; // LO calibration frequency
    double freq_throw = -40.0; // throw of frequency switch in MHz
    bool retunelo = true; // Whether LO retuning is enabled
    double deltanu = 1.0; // minimum effective resolution of the calibrated data
    int data_time = 4; // time between subsequent data readouts
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
}{
    // Initial computations
    {int,int,bool} calinit = HIFICalInit(band,lo_freq,deltanu,data_time);
    int used_datatime = calinit{0};
    int n_inttime = calinit{1};
    bool retuning = calinit{2} && retunelo;
    // Perform zero and comb measurement
    ZeroCombMeasurement(band,lo_freq,used_datatime,backendreadoutparms);
    // No we perform the actual hot-cold measurement - 2 frequencies
    int danglingreadout = HIFI_DoubleCalibrate_hot_cold(band,lo_freq,used_datatime,n_inttime,backendreadoutparms,retuning);
    // Retune and another load if we are in HEB bands
    if(retuning) {
        // we have to wait for readout
        delay(danglingreadout);
        // Another LO vector scan at the same frequency for a stable HEB operation
        // For FSW measurements a full preamble of 2xLCU_Configure is needed
        // as for a new setting (not fully confirmed yet, but safe solution !) 
        HIFITuneFreqFsw(band,tuning_freq,tuning_freq + freq_throw,true,"");
        danglingreadout = HIFI_DoubleCalibrate_hot_cold(band,lo_freq,used_datatime,n_inttime,backendreadoutparms,false);
    }
}

// Get standard load read out data cycle used only in fast-chop observations
int procedure GetStdLoadReadout {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] dead = CalibrationReader("stdloadreadout",["loadreadout"],band,lo_freq);

    return iceil(dead[0]);
}

/////////////////////////////////////////////////////////////////
// Fast chop dual beam switch observing mode
//
// The timing is defined as WBS timing, the HRS takes more data during
// the WBS read out, but this is ignored in the computations here.
// 
// Combination of four modules implementing the new structure 
//
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiPointProcFastDBS {
    /* Setup parameters */
    int naifid = 0; // Tracing object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Single Point - DBS fastChop",{data_time,0,n_switch_on,n_int_on,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,bool,int,int,int} pre_timing = FastDBS_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},bool,double,double} post_timing = DBS_post_timing(pre_timing,telescopetimes,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",post_timing{1},n_cycles);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    bool end_load = post_timing{1}{9};
    int shiftlength = post_timing{1}{10};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FastDBS_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,n_loadinterval,end_load,final_load,startobs,telescopetimes,loadlength,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastDBS_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBS_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,n_seq * n_int_on * (n_load + 1),tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

{string,double,double}[] procedure HifiPointModeDBSSequencerInit {
    string modeName = "dbs";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // Get the drift parameters to compute the drift noise
    {double,double} phaselengths = DBSPhaseLengths(band,lo_freq,effResolution,continuumDetection,oneGHzReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_switch_on_guess = imax(iceil(phaselengths{0} / (2.0 * double(data_time_guess))),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,2 * n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)}];

    return retvalues;
}

// Spectrometer configuration for slow chop, low level procedure
// Specific for hotcold or chopper calib cases (longer del_wbs)
int[] procedure Configure_Spectrometer_hc_slow_chop_proc_fm {
    string band = "1a"; // HIFI band
    int integ_time = 8; //Total integration time in sec. for the two phases !
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Compute data_time and n_switch use the wrapper
    int[] res = ConfigSlowChop(integ_time,"chopcal",band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_switch = res[1];
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS.
    // The deadtimes output is not used at ILT level.
    {double,double} dtimes = ConfigSpectroscopySlowChop_IST(data_time,n_switch,"chopcal",band,0.0,backendreadoutparms,true);
    //

    return res;
}

//
//Set LOU to nominal, block
//Set LOU in nominal mode with no
//channel selected
block Set_LO_Nominal_block_fm HIFI 3626 {
}{
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_delays",["set_to_nominal_delay"],"0",0.0);
    int set_to_nominal_delay = iround(result[0]{0});
    //
    Hifi_HIFI_HL_Normal($BBID);
    delay(set_to_nominal_delay);
    //
}

////////////////////////////////////
// Special DBS raster  - cross observing mode
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcDBSCross {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the two raster lines
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Mapping - DBS Cross Map slowChop",{data_time,0,0,n_switch_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = DBSRaster_pre_timing(2,npoints,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,double[],double[],int[],double,double,int,int,int,int,int,int} tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = custom_map_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSCross_post_timing(pre_timing,telescopetimes,npoints,n_switch_on,n_cycles,load_interval,false);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",post_timing{1},n_cycles);
    telescopetimes = custom_map_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int scansize = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        DBSRaster_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,true);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = DBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,2,npoints,n_cycles,n_seq * imax(n_load,1),tact);
    // Correct for double counting of central point
    // The central point noise is returned only
    double multiplier = sqrt(0.5);
    noisevalues{0} = noisevalues{0} * multiplier;
    noisevalues{1} = noisevalues{1} * multiplier;
    noisevalues{2} = noisevalues{2} * multiplier;
    noisevalues{3} = noisevalues{3} * multiplier;
    noisevalues{4} = noisevalues{4} / multiplier;
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// FPU Standby with chopper switched on. HBB is also ON  per default, block
block Band0_chopper_on_fm HIFI 3297 {
    string band = "0"; // HIFI band
    string chop_loop = "CLOSE"; // Chopper Loop status
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    result_d = ConfigurationReader("name_confilfpu",["bias_standby_h","diplexer_standby_h","bias_standby_v","diplexer_standby_v","diplex_h_ctrl_mode","diplex_v_ctrl_mode","chop_M3right"],band,0.0);
    //
    double bias_H = result_d[0]{0};
    double diplex_H = result_d[1]{0};
    double bias_V = result_d[2]{0};
    double diplex_V = result_d[3]{0};
    int diplex_h_ctrl_mode = iround(result_d[4]{0});
    int diplex_v_ctrl_mode = iround(result_d[5]{0});
    //
    //Retrieve magnets Magnet are so far at maximum value. Now set to nominal
    double magnetcurrent_H = result_d[1]{0};
    double magnetcurrent_V = result_d[4]{0};
    //
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_standby_h","magnet_standby_v"],band,0.0);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,0.0);
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
}

////////////////////////////////////
// Blocks
////////////////////////////////////
// Simulating PU report packet emission
block Simulate_PU_block_ops HIFI 7822 {
}{
    StartBlock_ops();
    mois_step("Send simulated micro-rotations to ACMS");
    int hifi_HI_microrot_y = 5;
    // HI_microrot_y
    int hifi_HI_microrot_z = 7;
    // HI_microrot_z
    Hifi_HIFI_simulate_peakup(hifi_HI_microrot_y,hifi_HI_microrot_z);
    delay(1);
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the OTF observing mode
procedure OTFFSwitch_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_perline = 10; // Number of frequency switch cycles per line
    int n_switch_off = 3; // Number of frequency switch cycles on OFF
    int nlines_tot = 1; // Total number of lines to scan
    int n_linesperscan = 1; // Number of lines between two OFFs
    int n_loadinterval = 1; // number of nods before a load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,2,2,40,10,20,21,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int toffslew = telescopetimes[6];
    // slew dead time between points
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] onrates = dataparms{1};
    dataparms = DataTaking(backendreadoutparms,data_time_off);
    double[] offrates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // Count OFFs by hand, their counter is not returned in the state array
    int ioff = 0;
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFIFsw(band,lo_freq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
        }
        if(state[0] == 4) {
            // OFF Integration
            HIFIConfigureFSwitchIntegration(data_time_off,n_switch_off,band,lo_freq,backendreadoutparms);
            HIFIFSwitchOffIntegration(data_time_off,n_switch_off,band,lo_freq,offrates);
            // OFF counter
            ioff = ioff + 1;
            // Check for normal slew after OFF
            if(state[2] * state[3] < nlines_tot) {
                HIFIActiveHK("normal",toffslew);
            }
        }
        if(state[0] == 8) {
            // OTF integration
            // Check whether we come from the OFF
            if((state[2] + n_linesperscan - 1) % n_linesperscan == 0) {
                HIFIConfigureFSwitchIntegration(data_time,n_perline,band,lo_freq,backendreadoutparms);
            }
            HIFIFSwitchOnIntegration(data_time,n_perline,band,lo_freq,onrates);
            // Check for normal slew towards the OFF
            if(state[2] % n_linesperscan == 0) {
                if(ioff % n_loadinterval > 0) {
                    HIFIActiveHK("normal",toffslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load slew
            delay(readoutdead);
            DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
        }
        if(state[0] == 5) {
            delay(readoutdead);
            HIFICloseObs();
        }
    }
}

//Set LCU6Ha back to standby status, procedure
procedure LCU6Ha_standby_proc_fm {
    string band = "7a"; // HIFI band
    double lo_freq = 1700.0 in [1700.0,1800.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

//HIFI-COP-2.3-Param-Scan block0: TPF maker
procedure TPF_maker_paramscan {
    int index = 1 in [1,2]; // Test case index as of config_paramscan_COP.config
}{
    //Read all band+param to perform
    string tab = "config_paramscan_COP.config";
    int total = table_size(tab);
    string band = slookup(tab,"" + index,"band");
    //
    //Switch-on LO
    //We use a constant frequency for each band, regardless of the input
    double lo_freq = 0.0;
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq","midfreq","keyfreqwarm","keyfreq_dummy"],band,0.0);
    lo_freq = result_d[0];
    //this is for cold operations
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlcutune = "name_configlcutune_a";
    string name_configlotune = "name_configlotune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlcutune = "name_configlcutune_b";
        name_configlotune = "name_configlotune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["switch_on_delay","config_lo_delay"],band,lo_freq);
    int switch_on_delay = iround(result[0]{0});
    int config_lo_delay = iround(result[1]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    drain2_v = cresult[0];
    //
    //Generate TPF parameters
    //Convert into raw:
    int g1 = convert_to_raw("hifi_HL_Gate1_7B_V",gate1_v);
    int g2 = convert_to_raw("hifi_HL_Gate2_7B_V",gate2_v);
    int vd1 = convert_to_raw("hifi_HL_Drain1_7B_V",drain1_v);
    //convert_to_raw does not work for params defined through TextualCalibrationCurves
    //The convertion is:
    if(curlim1 == "1.5") {
        int curl1 = 0;
    }
    if(curlim1 == "1.4") {
        curl1 = 2;
    }
    if(curlim1 == "1.3") {
        curl1 = 1;
    }
    if(curlim1 == "1.22") {
        curl1 = 3;
    }
    //
    if(curlim2 == "1.5") {
        int curl2 = 0;
    }
    if(curlim2 == "1.4") {
        curl2 = 2;
    }
    if(curlim2 == "1.3") {
        curl2 = 1;
    }
    if(curlim2 == "1.22") {
        curl2 = 3;
    }
    int vd2 = convert_to_raw("hifi_HL_Drain2_7B_V",drain2_v);
    int mm1 = convert_to_raw("hifi_HL_M1_7B_V",m1_v);
    int mm2 = convert_to_raw("hifi_HL_M2_7B_V",m2_v);
    Hifi_HIFI_WBS_Zero(mm1);
    Hifi_HIFI_WBS_Zero(mm2);
    Hifi_HIFI_WBS_Zero(g1);
    Hifi_HIFI_WBS_Zero(g2);
    Hifi_HIFI_WBS_Zero(vd1);
    Hifi_HIFI_WBS_Zero(curl1);
    Hifi_HIFI_WBS_Zero(vd2);
    Hifi_HIFI_WBS_Zero(curl2);
    //
    //Parameters from LO_tuning_w_M1M2_block_fm(band,lo_freq,m1,m2)
    //Read all band+param to perform
    lo_freq = dlookup(tab,"" + index,"lofreq");
    cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    gate1_v = cresult[0];
    gate2_v = cresult[1];
    drain1_v = cresult[2];
    drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    resu = ComputeLSU_A_M_R(band,lo_freq);
    lsu_main = resu[0];
    lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    curlim1 = result[0]{1};
    curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    //The automatic tuning shall use the min of the nominal best-guess and Vd2max - 100mV
    double middle_d2 = min(result[0]{0},drain2_bluemax - 0.1);
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    //Convert into raw:
    g1 = convert_to_raw("hifi_HL_Gate1_7B_V",gate1_v);
    g2 = convert_to_raw("hifi_HL_Gate2_7B_V",gate2_v);
    vd1 = convert_to_raw("hifi_HL_Drain1_7B_V",drain1_v);
    //convert_to_raw does not work for params defined through TextualCalibrationCurves
    //The convertion is:
    if(curlim1 == "1.5") {
        curl1 = 0;
    }
    if(curlim1 == "1.4") {
        curl1 = 2;
    }
    if(curlim1 == "1.3") {
        curl1 = 1;
    }
    if(curlim1 == "1.22") {
        curl1 = 3;
    }
    //
    if(curlim2 == "1.5") {
        curl2 = 0;
    }
    if(curlim2 == "1.4") {
        curl2 = 2;
    }
    if(curlim2 == "1.3") {
        curl2 = 1;
    }
    if(curlim2 == "1.22") {
        curl2 = 3;
    }
    vd2 = convert_to_raw("hifi_HL_Drain2_7B_V",drain2_v_start);
    //Read all band+param to perform
    double m1_min = dlookup(tab,"" + index,"m1_1");
    double m1_max = dlookup(tab,"" + index,"m1_2");
    double m1_step = dlookup(tab,"" + index,"m1_step");
    double m2_min = dlookup(tab,"" + index,"m2_1");
    double m2_max = dlookup(tab,"" + index,"m2_2");
    double m2_step = dlookup(tab,"" + index,"m2_step");
    double bias_min = dlookup(tab,"" + index,"bias_1");
    double bias_max = dlookup(tab,"" + index,"bias_2");
    double bias_step = dlookup(tab,"" + index,"bias_step");
    double imix_min = dlookup(tab,"" + index,"imix_1");
    double imix_max = dlookup(tab,"" + index,"imix_2");
    double imix_step = dlookup(tab,"" + index,"imix_step");
    double m1 = 0.0;
    double m2 = 0.0;
    //Phase 1 measurement: loop on M1 and M2
    m1 = m1_min;
    //Loop on M1
    while(m1 <= m1_max) {
        //Loop on m2: cancelled for the moment - SCR-2460
        m2 = m2_min;
        //while (m2<=m2_max) {
        //
        mm1 = convert_to_raw("hifi_HL_M1_7B_V",m1);
        mm2 = convert_to_raw("hifi_HL_M2_7B_V",m2);
        //Implementation of SCR-2460: for the time being, M2 is fixed to its nominal value - no scan
        result = ConfigurationReader(name_configlcu,["m2_v"],band,lo_freq);
        m2 = result[0]{0};
        mm2 = convert_to_raw("hifi_HL_M2_7B_V",m2);
        //
        //Values for pre-amble
        Hifi_HIFI_WBS_Zero(mm1);
        Hifi_HIFI_WBS_Zero(mm2);
        Hifi_HIFI_WBS_Zero(g1);
        Hifi_HIFI_WBS_Zero(g2);
        Hifi_HIFI_WBS_Zero(vd1);
        Hifi_HIFI_WBS_Zero(curl1);
        Hifi_HIFI_WBS_Zero(vd2);
        Hifi_HIFI_WBS_Zero(curl2);
        //Values for vector scan
        Hifi_HIFI_WBS_Zero(mm1);
        Hifi_HIFI_WBS_Zero(mm2);
        Hifi_HIFI_WBS_Zero(g1);
        Hifi_HIFI_WBS_Zero(g2);
        Hifi_HIFI_WBS_Zero(vd1);
        Hifi_HIFI_WBS_Zero(curl1);
        Hifi_HIFI_WBS_Zero(vd2);
        Hifi_HIFI_WBS_Zero(curl2);
        //
        message(band + ", " + lo_freq + ", " + m1 + ", " + m2);
        //
        //m2 = m2+m2_step;  
        //} //end loop m2
        m1 = m1 + m1_step;
    }
    //end loop m1
}

//LO parameter scan without HotCold measurement
//for Band 1a
procedure LCU1a_power_scan_without_Tsys {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4
    double lo_freq = 500.0 in [488.0,552.0]; //LO frequency
    double param_min = 1.0; //Min. of scanned parameter
    double param_max = 2.0; //Max. of scanned parameter
    double step_size = 0.1; //Step size
    string param_name = "D2"; //Code of scanned parameter: M1,M2,G1,G2,D1,D2.
}{
    error("This module is obsolete: use LCU_power_scan_without_Tsys  instead");
}

// LO settling time for a LO sub-band change, procedure. 
// Measures series of spectra while switching from
// one sub-band to another
procedure LO_Settling_time_proc_fm {
    string band_a = "1a" in ["1a","2a","3a","4a","5a","6a","7a"]; // HIFI band a
    string band_b = "1b" in ["1b","2b","3b","4b","5b","6b","7b"]; // HIFI band a
    int int_time1 = 3600; //Integration time after first tuning
    int int_time2 = 600; //Integration time after first and second switch
    double lo_freq_a = 500.0; //LO frequency in sub-band a
    double lo_freq_b = 600.0; //LO frequency in sub-band b
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //
    //Get cold position
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["chop_cold"],band_a,0.0);
    double chop = result_d[0]{0};
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band_a);
    }
    //Set up mixer for lo_freq_a
    Init_MSA_fm(band_a,"CLOSE",lo_freq_a,"ON");
    LO_Settling_time_first_tuning_fm(band_a,int_time1,lo_freq_a,backend);
    //
    Init_MSA_fm(band_b,"CLOSE",lo_freq_b,"ON");
    LO_Settling_time_second_tuning_fm(band_b,int_time2,lo_freq_b,backend);
    //
    Init_MSA_fm(band_a,"CLOSE",lo_freq_a,"ON");
    LO_Settling_time_third_tuning_fm(band_a,int_time2,lo_freq_a,backend);
    //
}

{int,double,double,double,double,double} obs HifiMappingModeFSwitchOTFNoRef {
    string modeName = "fs-raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period defines number of lines between two loads
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Mapping - OTF Map Frequency Switch noRef",{data_time,0,0,n_switch_on,0,0,0,0,n_cycles,load_interval});
    // Auxiliary routine for API parameter correction
    {double,double,int} mapused = ValidMapSize(band,lo_freq,lineDistance,nlines,stepsize,npoints,2 * data_time * n_switch_on);
    double line_used = mapused{0};
    double scanvelocity = mapused{1};
    int npoints_used = mapused{2};
    // Call first part of the timing computer
    {int,int,int,int,bool,int,int} pre_timing = OTFFSwitchNoRef_pre_timing(nlines,npoints_used,band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,int} tpar = OTFDoubleChopNoRef_telescope(naifid,onPosition,lineDistance,nlines,line_used,scanvelocity,band,lo_freq,n_cycles,pre_timing);
    // Dummy call to spacecraft command
    int[] telescopetimes = line_scan_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,bool,int,int},double,double} post_timing = OTFDoubleChopNoRef_post_timing(pre_timing,telescopetimes,nlines,data_time,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = OTFDoubleChopNoRef_telescope(naifid,onPosition,lineDistance,nlines,line_used,scanvelocity,band,lo_freq,n_cycles,post_timing{1});
    // Call telescope command
    telescopetimes = line_scan_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{0};
    bool end_load_on = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{2};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        OTFFSwitchNoRef_commanding(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,npoints_used * n_switch_on,n_loadinterval,nlines * n_cycles,end_load_on,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SingleChop_deadtimes("fs",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,npoints_used * n_switch_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = FSwitchNoRef_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_switch_on * n_cycles,tscan,tdead);
    // Evaluate performance
    OTFDoubleChopNoRef_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints_used,n_switch_on * n_cycles,true,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//Get diplexer setting using "real" frequencies
double[] procedure Get_Diplexer_setting {
    string band = "3a" in ["3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 810.0; //LO frequency
}{
    //Compute real frequency
    double real_lo_freq = Compute_Real_Freq(band,lo_freq);
    {double,string}[] result_d = ConfigurationReader("name_confildipl",["diplex_h_a","diplex_v_a","diplex_h_b","diplex_v_b"],band,lo_freq);
    if(band == "3a" || band == "4a" || band == "6a" || band == "7a") {
        double[] final_setting = [result_d[0]{0},result_d[1]{0}];
    } else {
        final_setting = [result_d[2]{0},result_d[3]{0}];
    }

    return final_setting;
}

// Normal combination of zero and comb measurement 
// 1s integration time, only WBS, maximum windows
// Inherited from blocks 3604 and 3605
//
// Returns dangling transmission time
//
int block WBS_Zero_Comb HIFI 6004 {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double lo_freq = 978200.0; // LO frequency
}{
    // Get delays 
    {double,string}[] result = ConfigurationReader("name_delays",["wbs_comb_delay"],band,lo_freq);
    int wbs_comb_delay = iround(result[0]{0});
    // data frame transmission time (always 2 spectra)
    int data_time = wbs_comb_delay / 2;
    int rest_delay = wbs_comb_delay - 2 * data_time;
    wbs_comb_delay = wbs_comb_delay - rest_delay;
    // Data rate computation
    // The HIFI command is restricted to always read out both full WBS
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} fullreadoutparms = FrequencyCalibrationParms(true,true,false,false);
    // data rate and read-out time
    {int,double[]} fdataparms = AllDataRates(fullreadoutparms,data_time,false);
    int readout = fdataparms{0};
    // Get attenuators for comb measurement
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_att_band4_comb","hwh_att_band3_comb","hwh_att_band2_comb","hwh_att_band1_comb","hwh_att_in_comb","hwv_att_band4_comb","hwv_att_band3_comb","hwv_att_band2_comb","hwv_att_band1_comb","hwv_att_in_comb"],band,0.0);
    int hwh_att_band4 = iround(result_d[0]{0});
    int hwh_att_band3 = iround(result_d[1]{0});
    int hwh_att_band2 = iround(result_d[2]{0});
    int hwh_att_band1 = iround(result_d[3]{0});
    int hwh_att_in = iround(result_d[4]{0});
    int hwv_att_band4 = iround(result_d[5]{0});
    int hwv_att_band3 = iround(result_d[6]{0});
    int hwv_att_band2 = iround(result_d[7]{0});
    int hwv_att_band1 = iround(result_d[8]{0});
    int hwv_att_in = iround(result_d[9]{0});
    // 
    // set data rates
    non_ess_hk_data_rate(fdataparms{1}[2] / 1024.0);
    data_rate(fdataparms{1}[0] / 1024.0);
    // Call command
    Hifi_HIFI_WBS_Comb($BBID,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    // Currently I ignore that the COMB ends with ZERO=on (SCR 618)
    delay(wbs_comb_delay);
    // reset data rates
    non_ess_hk_data_rate(fdataparms{1}[1] / 1024.0);
    data_rate(0.0);
    delay(rest_delay);
    //
    // additional delay for packet transmission before next zero depends
    // on zero duration - needs to be introduced on higher level

    return readout;
}

// Configuration for frequency-switch integration
block HIFIConfigureFSwitchIntegration HIFI 6037 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used, channel windows}
}{
    // Call procedure doing the work
    ConfigureSpectroscopy(data_time,2 * n_cycle,"fs",band,lo_freq,backendreadoutparms);
}

// HRS partial configuration, procedure
// Configures the LO and attenuators
procedure HRS_config_att_lo_fm {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["mr","mr"]; //HRS resolution code
}{
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double hrsH_ATT_U1 = result[1]{0};
    double hrsH_ATT_L1 = result[2]{0};
    double hrsH_ATT_U2 = result[3]{0};
    double hrsH_ATT_L2 = result[4]{0};
    double hrsH_ATT_U3 = result[5]{0};
    double hrsH_ATT_L3 = result[6]{0};
    double hrsH_ATT_U4 = result[7]{0};
    double hrsH_ATT_L4 = result[8]{0};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double hrsV_ATT_U1 = result[1]{0};
    double hrsV_ATT_L1 = result[2]{0};
    double hrsV_ATT_U2 = result[3]{0};
    double hrsV_ATT_L2 = result[4]{0};
    double hrsV_ATT_U3 = result[5]{0};
    double hrsV_ATT_L3 = result[6]{0};
    double hrsV_ATT_U4 = result[7]{0};
    double hrsV_ATT_L4 = result[8]{0};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_ATT_U1,hrsH_ATT_L1,hrsH_ATT_U2,hrsH_ATT_L2,hrsH_ATT_U3,hrsH_ATT_L3,hrsH_ATT_U4,hrsH_ATT_L4,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
    // 
    //delay(hrs_config_delay);
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsV_ATT_U1,hrsV_ATT_L1,hrsV_ATT_U2,hrsV_ATT_L2,hrsV_ATT_U3,hrsV_ATT_L3,hrsV_ATT_U4,hrsV_ATT_L4,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
    // 
    delay(hrs_config_delay);
}

// Functional test with pumped mixer, procedure
procedure FT_pumped {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,etc
    int integ_time = 4; //Integration time
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    double lo_freq = 500.0; //LO frequency
}{
    //
    //WBS calibration. Attenuators are set later in the magnet tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_config_block_fm(band);
        WBS_calib_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_config_block_fm(band,hrs_mode);
    }
    //
    //Re-Configure spectrometer integration
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    IVcurve_pumped_fm(band,lo_freq);
    //
    //Does a magnet tuning: only up to band 5 since band6-7 have no magnets
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        Magnet_tuning_block_fm(band,lo_freq,"HRS",40);
    }
    //
    //Go on hot load
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //Tune backends on the hot load
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_tune_block_fm(band);
    }
    //Reconfigure spectrometer integration after tuning
    int[] res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //Radiometry on internal loads
    Hot_cold(band,hrs_mode,backend,res[0] * res[1],"tp",0,0);
    //Back to middle of M3
    Chopper_Rotation_block_fm(band,"chop_hot_ang","chop_M3_ang");
}

/////////////////////////////////////////////////////////////////
// Procedure to filter only those attenuator settings that are used
double[][] procedure GetSScanLevelGrid {
    string band = "4a"; // HIFI band
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    double[] freqgrid = [978053.7,978301.8,978381.1]; // frequency grid
    int groupnumber = 1; // Number of frequency groups
    int[][] grouporder = [[0],[0]]; // Sequence to trace frequency points in groups
}{
    // Reduce frequency field - select center frequency of groups only
    if(groupnumber < length(freqgrid)) {
        int nfreq = length(freqgrid);
        double[] redfreq = [];
        int oldindex = 0;
        int groupsize = nfreq / groupnumber;
        // It is not clear whether grouporder[0,0] or grouporder[1,0]
        // is the better point. First better for DBS, second for NoRef.
        for(int j1 = 0 .. groupnumber - 1) {
            oldindex = j1 * groupsize + grouporder[0][0];
            redfreq[j1] = freqgrid[oldindex];
        }
    } else {
        redfreq = freqgrid;
    }
    // Make field of subbands that are used
    int idest = 0;
    int[] usedsubbands = [];
    for(int i = 0 .. 3) {
        if(wbs1{0} && wbs1{1}[i][1] - wbs1{1}[i][0] > 0) {
            usedsubbands[idest] = i;
            idest = idest + 1;
        }
    }
    for(int ii = 0 .. 3) {
        if(wbs2{0} && wbs2{1}[ii][1] - wbs2{1}[ii][0] > 0) {
            usedsubbands[idest] = ii + 4;
            idest = idest + 1;
        }
    }
    // Create dB grid needed for backend retuning 
    double[][] retunegrid = GetSScanLevels(band,redfreq,usedsubbands);

    return retunegrid;
}

// Initialisation, block with all IF set ON but unpumped mixers
block Init_all_IF_fm HIFI 3215 {
    string band = "1a"; // HIFI band
    string mixer_polarization = "B" in ["H","V","B"]; //Polarization: H, V, or both (B) 
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // Check whether H-polar is requested
    if(mixer_polarization == "V") {
        result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],"0",0.0);
        //
        volt_H_FIF_1 = result_d[0]{0};
        curr_H_FIF_1 = result_d[1]{0};
        volt_H_FIF_2 = result_d[2]{0};
        curr_H_FIF_2 = result_d[3]{0};
        //
        volt_H_SIF_1 = result_d[4]{0};
        curr_H_SIF_1 = result_d[5]{0};
        volt_H_SIF_2 = result_d[6]{0};
        curr_H_SIF_2 = result_d[7]{0};
        volt_H_SIF_3 = result_d[8]{0};
        curr_H_SIF_3 = result_d[9]{0};
    }
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    // Check whether H-polar is requested
    if(mixer_polarization == "H") {
        result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],"0",0.0);
        //
        volt_V_FIF_1 = result_d[0]{0};
        curr_V_FIF_1 = result_d[1]{0};
        volt_V_FIF_2 = result_d[2]{0};
        curr_V_FIF_2 = result_d[3]{0};
        //
        volt_V_SIF_1 = result_d[4]{0};
        curr_V_SIF_1 = result_d[5]{0};
        volt_V_SIF_2 = result_d[6]{0};
        curr_V_SIF_2 = result_d[7]{0};
        volt_V_SIF_3 = result_d[8]{0};
        curr_V_SIF_3 = result_d[9]{0};
    }
    //
    string chop_sine_s = "ON";
    string chop_loop = "CLOSE";
    //Chopper is not used anyway
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current_on"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    //Junctions do not need to be biased, nor should diplexers be moved
    double bias_H = 0.5;
    double magnetcurrent_H = 0.0;
    double bias_V = 0.5;
    double magnetcurrent_V = 0.0;
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double chopper = 0.0;
    //
    //
    chopper = Check_Chopper_Prime_Redundant(chopper);
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
}

////////////////////////////////////
// Functions for two dimensional vectors, e.g. coordinates on the sky
// Multiply a vector defined as a tuple with a scaler defined as a double
{double,double} procedure MultiplyScalarVector {
    double scalar = 1.0;
    {double,double} vector = {1.0,1.0};
}{

    return {vector{0} * scalar,vector{1} * scalar};
}

//HIFI-COP-2.1-DPL-RespTime
//Check diplexer response time for all diplexer bands
obs HifiEng_Diplexer_Response_time_COP {
    string band = "3a" in ["3a","4a","6a","7a"]; //Mixer diplexer band: 3a, 4a, 6a or 7a
    string mixer_polarization = "H"; //mixer polarization: H or V
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Diplexer_Response_time_COP_proc_ops(band,mixer_polarization));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Diplexer_Response_time_COP_proc_ops(band,mixer_polarization);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

////////////////////////////////////
// OTF observing mode
// 
// Combination of four modules implementing the new structure 
//
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcOTF {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the map center
    double dec = 0.0; // DEC coordinate of the map center
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    bool refSelected = true; // Dummy parameter required by HSPOT
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints = 10 in [1,720]; // Number of data dumps per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,5]; // chunk size given by the data rates and optimum speed
    int n_int_on = 1 in [1,1800]; // Supersamplingfactor
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Mapping - OTF Map Position Switch",{data_time,0,n_int_on,0,n_switch_off,n_linesperscan,0,0,n_cycles,load_interval});
    // Auxiliary routine for API parameter correction
    {double,double,int} mapused = ValidMapSize(band,lo_freq,lineDistance,nlines,stepsize,npoints,data_time * n_int_on);
    double line_used = mapused{0};
    double scanvelocity = mapused{1};
    int npoints_used = mapused{2};
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int} pre_timing = OTFmap_pre_timing(nlines,npoints_used,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_linesperscan,n_switch_off,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,double,double,int,int,int,int,int} tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,pre_timing);
    // Dummy call to spacecraft command
    int[] telescopetimes = line_scan_with_off_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int},double,double} post_timing = OTFmap_post_timing(pre_timing,telescopetimes,data_time,n_linesperscan,n_cycles,load_interval);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,post_timing{1});
    // Call telescope command
    telescopetimes = line_scan_with_off_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int n_pp = post_timing{1}{0};
    int n_scans = post_timing{1}{1};
    int loadlength = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{5};
    double tscan = post_timing{2};
    double tdead = post_timing{3};
    // telescope time
    int slewtime = telescopetimes[6];
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        OTFmap_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,nlines * n_cycles,n_linesperscan,n_switch_off,n_pp,n_loadinterval,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check])
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = OTFmap_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_linesperscan,n_switch_off,n_pp,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = OTFmap_noisecomputer(band,lo_freq,effResolution,oneGHzReference,nlines,npoints_used,n_int_on,n_linesperscan,n_cycles,slewtime,tscan,tact);
    // Evaluate performance
    OTF_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints_used,n_scans,n_cycles,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//Procedure to store currently tuned frequency, procedure
procedure HIFI_HL_store_tm_proc_fm {
}{
    Hifi_HIFI_HL_store_tm($BBID);
    //This commands sends a request to get FSW1/2 into non-periodic HK 
    //Removed as of SPR-1747 
    //Hifi_HIFI_LCU_macro_buffers();
    delay(1);
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of DBS-raster observing mode
{int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} procedure DBSRaster_post_timing {
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = {4,10,4,21,1,1800,0,10,1,1,1,50,0}; // pre timing parameter list  
    int[] telescopetimes = [300,180,10,0,10,20,21,0,0,0];
    int nlines_tot = 1; // Number of rows in the map
    int npoints = 10; // Number of points per row
    int n_chop = 2; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800; // load period = f(band,lo_freq,eff_resolution{1})
    bool fastchop = false; // whether fast-chop is used instead of slow-chop
}{
    // Get all values from the pre_timing section
    int inttime = pre_timing{0};
    int pointing = pre_timing{1};
    int readouttime = pre_timing{2};
    int loadlength = pre_timing{3};
    int jitterdead = pre_timing{4};
    int load_spacing = pre_timing{5};
    int n_load = pre_timing{6};
    int n_loadinterval = pre_timing{7};
    int n_seq = pre_timing{8};
    int n_scans = pre_timing{9};
    int scansize = pre_timing{10};
    int initlength = pre_timing{11};
    int dangling = pre_timing{12};
    // Get all values from the telescope section  
    int telinit = telescopetimes[1];
    // Initial slew time
    int slewtime = telescopetimes[2];
    // Slew time to next point
    if(scansize > 1) {
        int nodtime = telescopetimes[4];
        // Slew time to second nod
        int slewline = telescopetimes[3];
        // Slew between lines
        int longslew = telescopetimes[5];
        // Actual slew time for load slew
        int returntime = telescopetimes[6];
        // Idle time between two phases
        int tend = telescopetimes[7];
        // Final deceleration time
    } else {
        nodtime = telescopetimes[5];
        slewline = telescopetimes[4];
        longslew = telescopetimes[6];
        returntime = telescopetimes[3];
        tend = telescopetimes[9];
    }
    int shortmove = imin(slewtime,slewline);
    shortmove = imin(shortmove,returntime);
    // Total number of scans
    int n_tot = n_scans * n_cycles;
    ///////////////////////
    // Long computation for scansize > 1 to obtain all slew durations
    {int,int} alldeadtimes = Raster_slewtimes(nlines_tot,npoints,n_cycles,scansize,nodtime,slewtime,slewline,returntime);
    int tinscandead = alldeadtimes{0};
    int toutscandead = alldeadtimes{1};
    // Compute total duration of measurement and average scan length
    int totalscantime = n_tot * (2 * pointing * scansize) + tinscandead;
    // approximate scan time for load comparison
    int scan_time = iceil(double(totalscantime) / double(2 * n_tot));
    if(load_spacing > 2 * scan_time) {
        n_seq = n_chop;
        pointing = inttime + jitterdead;
        bool end_load = false;
    } else {
        // It could happen that the slew extends the scan too much - catch
        if(scansize > 1) {
            SError("Number of points in one scan too large for load period.");
        }
        n_load = n_load + 1;
        n_seq = n_chop / n_load;
        if(n_seq < 1) {
            SError("Transfer cycle too long relative to load period.");
        }
        // adjust pointing time to include load measurements
        int loadappend = imax(loadlength - shortmove,0);
        end_load = true;
        // Computation for slow-chop or fast-chop
        if(fastchop) {
            inttime = n_seq * n_load * readouttime;
        } else {
            inttime = 2 * n_seq * n_load * readouttime;
        }
        pointing = inttime + loadappend + (n_load - 1) * loadlength + jitterdead;
    }
    totalscantime = n_tot * (2 * pointing * scansize) + tinscandead + toutscandead;
    scan_time = iceil(double(totalscantime) / double(2 * n_tot));
    // compute the load interval in case of short scan_time
    n_loadinterval = imax((load_interval - loadlength + nodtime) / (2 * scan_time),1);
    // Special treatment for nodding_raster due to limitations in API
    // Split into loads per point or per multiple points
    if(scansize == 1 && n_loadinterval > n_cycles) {
        n_loadinterval = n_cycles * (n_loadinterval / n_cycles);
        // Translate load waiting time into a hold after the point
        int holdlength = imax(loadlength - nodtime,0);
        longslew = nodtime + holdlength;
    } else {
        holdlength = 0;
    }
    // Special treatment for loads per point to compensate counter reset
    if(scansize == 1 && n_loadinterval < n_cycles) {
        int dangling_period = n_cycles % n_loadinterval;
        while((dangling_period + n_loadinterval) * 2 * scan_time > load_interval - loadlength + nodtime) {
            n_loadinterval = n_loadinterval - 1;
            dangling_period = n_cycles % n_loadinterval;
        }
        // Consistency check
        if(n_loadinterval < 1) {
            CError("Too short load period computed.");
        }
        int n_long = n_scans * (n_cycles / n_loadinterval);
    } else {
        n_long = n_tot / n_loadinterval;
    }
    // Compute total duration of measurement, correct for load nods
    totalscantime = n_tot * (2 * pointing * scansize) + tinscandead + n_long * (longslew - nodtime);
    // Average dead and scan time for drift estimate
    double tscan = double(totalscantime) / double(n_tot);
    double tdead = tscan - double(2 * inttime * scansize);
    // Count integration times of other points of one nod as dead time
    // Other points in the second nod are excluded from the scan
    double othertime = double((scansize - 1) * inttime);
    tdead = tdead + othertime;
    // Reduce scan time by the other points in the second nod phase
    tscan = tscan - othertime;
    // Determine need for final load measurement
    double rest = double(n_tot % n_loadinterval) + 0.5;
    bool final_load = rest > 0.5001 * double(n_loadinterval);
    // Compute total duration
    // The initial time is no longer contained in the total time  
    // int totaltime=imax(initlength,telinit);
    int totaltime = totalscantime + toutscandead;
    // Add dangling load time if not included in pointing
    // they are mutually exclusive, otherwise the readoutdelay applies
    if(final_load) {
        dangling = loadlength;
    }
    if(end_load) {
        dangling = loadlength - loadappend;
    }
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    totaltime = totaltime + dangling + tend;
    // show gyro-propagation messages
    if(scansize > 1) {
        GCPMessages(0,totalscantime,tend);
    } else {
        GCPMessages(pointing,totalscantime,tend);
    }
    // Return all the times needed in the observing mode modules

    return {totaltime,{inttime,pointing,readouttime,loadlength,holdlength,load_spacing,n_load,n_loadinterval,n_seq,n_scans,scansize,initlength,dangling},final_load,tscan,tdead};
}

//HIFI-COP-1.2-LO_FT
procedure COP_LO_FT_TPF_maker {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //
    double[] cresult_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = cresult_d[0];
    //applies to cold LO
    //
    //Get diplexer settings at this frequency
    int diplh = convert_to_raw("hifi_HF_CH1_DPACT_C",0.0);
    int diplv = convert_to_raw("hifi_HF_CV1_DPACT_C",0.0);
    if(band == "3a" || band == "3b" || band == "4a" || band == "4b" || band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplh = convert_to_raw("hifi_HF_CH1_DPACT_C",result_dip[0]);
        diplv = convert_to_raw("hifi_HF_CV1_DPACT_C",result_dip[1]);
    }
    Hifi_HIFI_WBS_Zero(diplh);
    Hifi_HIFI_WBS_Zero(diplv);
    //Switch on with safe Vd2
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    drain2_v = cresult[0];
    //Note: check that Vd2 is within the blue limits
    drain2_v = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v);
    //Send command: expect that we have already switched to NOMINAL
    //We set D2 to best guess and wait some time to stabilize chain temperature
    int bbid = 237043713;
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_safe_LCU_ch1a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_safe_LCU_ch1b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_safe_LCU_ch2a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_safe_LCU_ch2b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_safe_LCU_ch3a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_safe_LCU_ch3b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_safe_LCU_ch4a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_safe_LCU_ch4b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
    //Set heater to their switch-on value
    bbid = 236912641;
    string context = "nominal";
    cresult = CalibrationReader("name_loheater",["heater_nominal","heater_stby"],band,0.0);
    double hifi_HL_heater = cresult[0];
    if(context == "stby") {
        hifi_HL_heater = cresult[1];
    }
    Hifi_HIFI_HL_heater(bbid,hifi_HL_heater);
    //LO_SFT_proc_cop
    //Send command: expect that we have already switched to NOMINAL
    //We set D2 to best guess and wait some time to stabilize chain temperature
    bbid = 237043714;
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_safe_LCU_ch1a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_safe_LCU_ch1b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_safe_LCU_ch2a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_safe_LCU_ch2b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_safe_LCU_ch3a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_safe_LCU_ch3b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_safe_LCU_ch4a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_safe_LCU_ch4b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
    //Set heater to their switch-on value
    bbid = 236912642;
    context = "nominal";
    cresult = CalibrationReader("name_loheater",["heater_nominal","heater_stby"],band,0.0);
    hifi_HL_heater = cresult[0];
    if(context == "stby") {
        hifi_HL_heater = cresult[1];
    }
    Hifi_HIFI_HL_heater(bbid,hifi_HL_heater);
    //Send best-guess Vd2 for SFT
    cresult_d = CalibrationReader("name_keyfreq",["key_d2v_P","key_d2v_R"],band,0.0);
    //Check what d2_v to use depending on test circumstances
    drain2_v = cresult_d[0];
    //Value for prime case, and fm H/W
    if(prime_or_redundant == "redundant") {
        drain2_v = cresult_d[1];
    }
    //
    //Note: check that Vd2 is within the blue limits
    drain2_v = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v);
    bbid = 237043715;
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_safe_LCU_ch1a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_safe_LCU_ch1b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_safe_LCU_ch2a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_safe_LCU_ch2b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_safe_LCU_ch3a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_safe_LCU_ch3b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_safe_LCU_ch4a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_safe_LCU_ch4b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b(bbid,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
}

// Take slow chop spectra, block
block Spectro_slow_chop_block_fm HIFI 3607 {
    string band = "1a"; // HIFI band
    double[] chop_angle = [-1.0,+1.0]; //The two angles to chop between
    int[] timing_parms = [4,2]; //single readout time in sec. and n_wbs_start
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    int integ_time = timing_parms[0] * timing_parms[1];
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"slowchop",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    HIFI_Spectr_slow_chop_proc_fm(chop_angle[0],chop_angle[1]);
    //This probably needs to be adapted
    Apply_Slow_Chop_delay(integ_time,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// Switch HIFI off, mode
// Assumed to be in rescue mode when starting this mode
//
mode HifiManCmd_HIFI_Rescue_to_switched_off {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    Mode_status_check_rescue("failure");
    mois_comment("Switch from HIFI rescue to switch off: switches off the ICU");
    //Here ICU is not working properly so no obsid or HK handling
    //StartMode_block_ops();  
    string icu_subsys = "ICU_Prime";
    if(prime_or_redundant == "Red") {
        icu_subsys = "ICU_Red";
    }
    PDU_switch_off_block_ops(icu_subsys);
    //Here, HIFI is idle: the switch back to obsid = 0 is done just before ICU switched off
    //StopMode_block_ops () ;
    Mode_status_check_switched_off();
}

//  LCU3b configuration and tuning, procedure
procedure LCU3b_config_tune_proc_fm {
    string band = "3b"; // HIFI band
    double lo_freq = 900.0 in [852.0,953.0]; //LO frequency
    double drain_2_factor = 100.0; //Percentage factor of the targetted drain voltage
}{
    error("This module is obsolete: use LO_tuning_block_fm  instead");
}

// Stability test, procedure
// Measurement of internal cold in FSW mode
// In COP, look at the sky
procedure Proc_stability_freqswitch_COP {
    string band = "1a"; // HIFI band
    double lo_freq = 522.0; //The LO frequency
    double freq_throw = 50.0; //The frequency throw in MHz
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total (co-added) integration time of a phase in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    int freq_index = 1; //Frequency index to be applied
}{
    //
    //Tune to the two frequencies: the first frequency is the one
    //used to tune the backends
    //
    //Set Diplexer to the frequency used for the standing wave test
    //Implementation of SCR-2348
    string tabstwv = "config_stwvfreq.config";
    double bandnb = GetBandCode(band);
    double stwvfreq = dlookup(tabstwv,"" + iceil(bandnb),"freq" + freq_index);
    Set_Diplexer_current_FSW_block_fm(band,stwvfreq);
    //Old approach: diplexer at middle freq between FSW1 and FSW2
    //Set_Diplexer_current_FSW_block_fm(band,lo_freq+freq_throw/2000.);
    //
    //Set to FSW1
    LO_tuning_FSW_block_fm(band,lo_freq,lo_freq + freq_throw / 2000.0,true);
    //The frequency settings are automatically stored in register FSW1
    //
    //Configure backends
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        //WBS calibration
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    //
    //set to FSW2
    LO_tuning_FSW_block_fm(band,lo_freq + freq_throw / 1000.0,lo_freq + freq_throw / 2000.0,false);
    //The frequency settings are automatically stored in register FSW2
    //
    //Configure spectrometers integration after tuning: done later
    //Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_M3_ang");
    //Look at M3 for stability measurement
    //
    Stability_freqswitch_fm(band,n,integ_time,hrs_mode,backend);
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
    //2 sec. integration
}

// Rotate angle by -90 deg
double procedure RotateRight {
    double angle = 0.0; // Original angle
}{
    double fullcircle = 360.0;

    return (angle + fullcircle * 0.75) % fullcircle;
}

// WBS configuration with minimum attenuation, block
// Laser can be chosen
block WBS_config_min_att_w_laser_block_fm HIFI 3642 {
    string band = "1a"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
}{
    //Start_block();
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = 0;
    int hwh_att_band3 = 0;
    int hwh_att_band2 = 0;
    int hwh_att_band1 = 0;
    int hwh_att_in = 0;
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //delay(wbs_config_delay);
    //V-Polarization
    //Get configuration parameters
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = 0;
    int hwv_att_band3 = 0;
    int hwv_att_band2 = 0;
    int hwv_att_band1 = 0;
    int hwv_att_in = 0;
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    //Wait delay to allow all setting to be configured
    delay(wbs_config_delay);
}

//TM check when in Primary mode
procedure Mode_status_check_primary {
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
    string chopper_loop = "OPEN" in ["OPEN","CLOSE"]; //chopper loop status
}{
    mois_comment("Checking instrument status in primary mode");
    //General checks: not needed here as we won't be at that stage otherwise
    //FCU checks
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],"0",0.0);
    double calibcurrent = result_d[0]{0};
    //mois_tmcheck("Check that parameter HF_APR_CS_C is set to " + calibcurrent + " mA");
    //mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to " + chopper_loop);
    //WBS checks: not applicable: status unchanged
    //HRS Checks: not applicable: status unchanged
    //LOU Checks
    mois_tmcheck("Check that parameter HL_MODE_S is normal");
    mois_tmcheck("Check that parameter HL_Channel_S is Off");
}

// Treat each line separately - no optimization of consecutive lines
{int,int[]}[] procedure LcuGetMemoryRuns_ops {
    string section = "P" in ["P","R"]; // select prime or redundant LCU
}{
    string tab = "LcuMemoryPatch_" + section + ".config";
    int total = table_size(tab);
    {int,int[]}[] result = [];
    for(int line = 1 .. total) {
        string look = "" + line;
        int loc = ilookup(tab,look,"location");
        int val = ilookup(tab,look,"value");
        int[] value = [];
        value[0] = val;
        result[line - 1] = {loc,value};
    }

    return result;
}

/////////////////////////////////////////////////////////////////
// Auxiliary routine to determine the two loop phase durations  and
// the OFF resolution for all load-chop modes
{double,double,double,double} procedure LoadChopPhaseLengths {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
}{
    // limits from noise section
    // resolution of OFF phase
    double sw_resolution = GetLoadChopSWResolution(band,lo_freq);
    sw_resolution = max(effResolution{1},sw_resolution);
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    double allan_time_off = allanparms[0] * pow(1.0 / sw_resolution,binningexp);
    // Differential Allan variance
    allanparms = InterpolateSpecLChopAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double dalpha = allanparms[1];
    binningexp = 1.0 / allanparms[2];
    double dallan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // phase lengths
    double main_phase = 0.3 * dallan_time_lores;
    double chop_phase = 0.3 * allan_time_lores;
    double chop_phase_off = 0.3 * allan_time_off;
    // Constrain by load period
    int loadper = LoadPeriod(band,lo_freq,effResolution{0});
    main_phase = min(main_phase,0.4 * double(loadper));

    return {main_phase,chop_phase,chop_phase_off,sw_resolution};
}

////////////////////////////////////
// Peakup observing mode
// 
obs HifiEngPeakup {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the raster line
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    string backend = "WBS" in ["WBS","HRS"]; // backend to use - resolution
    string polarization = "H" in ["H","V"]; // backend to use - polarization
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = PeakupBackendSettings(backend,polarization,band,lo_freq,1);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    // Call first part of the timing computer
    {int,int,int,int,int,double,int,int} pre_timing = Peakup_pre_timing(3,3,band,lo_freq,hr1,hr2,wb1,wb2);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double} tpar = Peakup_telescope(naifid,onPosition,stepsize,3,3,band,lo_freq,pre_timing);
    int[] telescopetimes = basic_raster_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,double,int,int}} post_timing = Peakup_post_timing(pre_timing,telescopetimes,3,3);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = Peakup_telescope(naifid,onPosition,stepsize,3,3,band,lo_freq,post_timing{1});
    telescopetimes = basic_raster_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int data_time = post_timing{1}{2};
    int n_int = post_timing{1}{4};
    double eff_resolution = post_timing{1}{5};
    int initlength = post_timing{1}{6};
    int dangling = post_timing{1}{7};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    ///////////////////////////////////////////////////////////////////////
    // Call instrument commands
    Peakup_commanding(band,lo_freq,hr1,hr2,wb1,wb2,data_time,n_int,eff_resolution,stepsize,startobs,telescopetimes,loadlength);
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
}

//Check consistency between band and frequency inputs
//Should be invoked at the beginning of every mode !
bool procedure Check_Band_vs_Freq_proc_fm {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band   
    double lo_freq = 500.0; //LO frequency
}{
    bool go_ahead = true;
    bool go_ahead_a = true;
    bool go_ahead_b = true;
    //
    //Fetch LO limits
    {double,string}[] result = ConfigurationReader("name_configlo_a",["lo_a_low","lo_a_high"],band,lo_freq);
    double lo_a_low = result[0]{0};
    double lo_a_high = result[1]{0};
    result = ConfigurationReader("name_configlo_b",["lo_b_low","lo_b_high"],band,lo_freq);
    double lo_b_low = result[0]{0};
    double lo_b_high = result[1]{0};
    //
    if(band == "0" && (lo_freq < lo_a_low || lo_freq > lo_a_high)) {
        go_ahead_a = false;
    }
    if(band == "1a" && (lo_freq < lo_a_low || lo_freq > lo_a_high)) {
        go_ahead_a = false;
    }
    if(band == "1b" && (lo_freq < lo_b_low || lo_freq > lo_b_high)) {
        go_ahead_b = false;
    }
    if(band == "2a" && (lo_freq < lo_a_low || lo_freq > lo_a_high)) {
        go_ahead_a = false;
    }
    if(band == "2b" && (lo_freq < lo_b_low || lo_freq > lo_b_high)) {
        go_ahead_b = false;
    }
    if(band == "3a" && (lo_freq < lo_a_low || lo_freq > lo_a_high)) {
        go_ahead_a = false;
    }
    if(band == "3b" && (lo_freq < lo_b_low || lo_freq > lo_b_high)) {
        go_ahead_b = false;
    }
    if(band == "4a" && (lo_freq < lo_a_low || lo_freq > lo_a_high)) {
        go_ahead_a = false;
    }
    if(band == "4b" && (lo_freq < lo_b_low || lo_freq > lo_b_high)) {
        go_ahead_b = false;
    }
    if(band == "5a" && (lo_freq < lo_a_low || lo_freq > lo_a_high)) {
        go_ahead_a = false;
    }
    if(band == "5b" && (lo_freq < lo_b_low || lo_freq > lo_b_high)) {
        go_ahead_b = false;
    }
    if(band == "6a" && (lo_freq < lo_a_low || lo_freq > lo_a_high)) {
        go_ahead_a = false;
    }
    if(band == "6b" && (lo_freq < lo_b_low || lo_freq > lo_b_high)) {
        go_ahead_b = false;
    }
    if(band == "7a" && (lo_freq < lo_a_low || lo_freq > lo_a_high)) {
        go_ahead_a = false;
    }
    if(band == "7b" && (lo_freq < lo_b_low || lo_freq > lo_b_high)) {
        go_ahead_b = false;
    }
    if(go_ahead_a == false) {
        //debug_print("go_ahead is: " + go_ahead);
        error("LO frequency not within allowed range (" + lo_a_low + " to " + lo_a_high + " GHz) for band " + band);
        go_ahead = go_ahead_a;
    }
    if(go_ahead_b == false) {
        //debug_print("go_ahead is: " + go_ahead);
        error("LO frequency not within allowed range (" + lo_b_low + " to " + lo_b_high + " GHz) for band " + band);
        go_ahead = go_ahead_b;
    }
    //
    //Extra check for warm operations with dummies: only limited amount of frequencies allowed in config files
    //bool go_ahead_warm = Check_Band_vs_WarmFreq_proc_fm(band,lo_freq);
    //bool go_ahead_warm = Check_Band_vs_WarmKeyFreq_proc_fm(band,lo_freq);
    //if (go_ahead_warm == false) {
    //   go_ahead = go_ahead_warm;
    //   }

    return go_ahead;
}

////////////////////////////////////////////////////
// Building blocks used in general observations
//
// They call procedures which should be common between ILT and space
// Actual building blocks possible when numbers are
// assigned.
//
// Currently, these blocks contain the data rate computations.
/////////////////////////////////////////////////////////////////////////////
// Collection of identical procedures for continuous data read out
// calling different building blocks to make data distinguisable
// Set observation ID for the current observation - start of every obs
block HIFIInitObs HIFI 6000 {
}{
    // new delay to allow for insertion of BUSCONFIG by MPS 
    // email from Larry, October 19, 2007
    // applies only to RMS and SOVT - removed again in HSPOT version
    // delay(1);
    // Set ObsId as very first step
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CUS scripts for FPU.
// FPU FT scripts are found under fm_FT_FPU.cus
//
// DT - 17-Feb-06
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The modes
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//See fm_testmodes.cus
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The procedures
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Procedure checking and, if applicable, converting
//prime chopper sent voltage into redundant chopper sent voltage
double procedure Check_Chopper_Prime_Redundant {
    double chopper_angle = 0.0; //prime chopper voltage
}{
    //Check prime or redundant status
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant","p_to_r_coeff_0","p_to_r_coeff_1","p_to_r_coeff_2","prime_endstop_min","prime_endstop_max","red_endstop_min","red_endstop_max"],"0",0.0);
    double chop = chopper_angle;
    double prime_endstop_min = result_d[4]{0};
    double prime_endstop_max = result_d[5]{0};
    double red_endstop_min = result_d[6]{0};
    double red_endstop_max = result_d[7]{0};
    //Change chopper voltage if necessary   
    if(result_d[0]{1} == "redundant") {
        chop = result_d[3]{0} * pow(chop,2.0) + result_d[2]{0} * chop + result_d[1]{0};
    }
    //Now check the chopper angle is within the ranges
    if(result_d[0]{1} == "prime") {
        if(chop > prime_endstop_max || chop < prime_endstop_min) {
            error("The chopper voltage (requested is " + chop + " V) in " + result_d[0]{1} + " mode has to be between " + prime_endstop_min + " and " + prime_endstop_max + " V.");
        }
    }
    if(result_d[0]{1} == "redundant") {
        if(chop > red_endstop_max || chop < red_endstop_min) {
            error("The chopper voltage (requested is " + chop + " V) in " + result_d[0]{1} + " mode has to be between " + red_endstop_min + " and " + red_endstop_max + " V.");
        }
    }

    return chop;
}

//HIFI-COP-X-IF-FBk-Dip
obs HifiEng_IF_FBk_Dip_COP {
    string band = "3a" in ["3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI band
    int testtime = 3600; //total test time in seconds
}{
    //General parameters in use
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result_d[0];
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //  
    //Avoid high data-rates
    if(testtime % 3 == 0 && testtime % 4 == 0) {
        testtime = testtime + 4;
    }
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(IF_FBk_Dip_COP_proc_ops(band,lo_freq,hrs_mode,testtime,backend));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            IF_FBk_Dip_COP_proc_ops(band,lo_freq,hrs_mode,testtime,backend);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//HIFI-COP-3-FTP
procedure FT_pumped_COP_proc_ops {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int integ_time = 4;
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
}{
    //
    //Get list of frequencies for given band
    double[] cresult = CalibrationReader("name_keyfreq",["keyfreq","minfreq","maxfreq","midfreq","badfreq"],band,0.0);
    //      
    string current_subband = "0";
    //Loop on key frequencies per LO band
    for(int i = 0 .. 4) {
        //     
        //Wait an extra delay of 1 min for short term stabilization
        delay(60);
        Init_MSA_HBB_fm(band,"CLOSE",cresult[i],"ON");
        LO_tuning_block_fm(band,cresult[i]);
        //
        FT_pumped(band,hrs_mode,integ_time,backend,cresult[i]);
        //
        LCU_switch_off_block_fm();
        //
        FT_unpumped(band,hrs_mode,integ_time,backend);
    }
    //
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure FastSScanDBS_commanding {
    string band = "4a"; // HIFI band
    double reffreq = 978300.0; // Reference characteristic LO frequency 
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int grouplen = 1; // Number of frequency steps per nodding phase
    int[][] grouporder = [[0],[0]]; // Sequence to trace frequency points in both phases
    double[] freqgrid = [978053.7,978301.8,978381.1]; // Table of frequency points
    bool retuning = false; // need for WBS retuning
    double[] targetlevels = [1.0,1.0,1.0]; // WBS tuning levels
    int data_time = 10; // data dump interval
    int n_int = 20; // number chop cycles to integrate in ICU before transfer
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int allsteps = 4; // Total number of frequency pointing periods
    int n_bchop = 1; // Normal number of chop cycles per frequency and pointing
    int n_long = 1; // Chop cycles per frequency and pointing without retuning
    int n_loadinterval = 1; // number of nods before a load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int shiftlength = 10; // Shift of the loop start relative to the pointing
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    // First frequency
    double runningfreq = freqgrid[grouporder[0][0]];
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time / 2);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,true);
    int readoutdead = FastChopReadoutDelay(band,reffreq,backendreadoutparms);
    // recompute load duration for initial load measurement
    int load_datatime = GetStdLoadReadout(band,reffreq);
    int loadlength = duration(SScanLoadMeasurement(band,runningfreq,reffreq,true,eff_resolution{0},load_datatime,backendreadoutparms));
    loadlength = loadlength + readoutdead;
    bool retuneload = n_loadinterval > 1;
    // Tuning levels
    string[] targetnames = TargetNames(band,reffreq,retuning,targetlevels);
    string target = targetnames[0];
    // All commands with a duration possibly depending on the frequency
    // are taken at the reference frequency to guarantee synchonization
    // Declare auxiliary variables to be used in the loops
    int i_freqcycles = 0;
    int i_group = 0;
    int i_phase = 0;
    int[] choppars = [1,0];
    // variables storing the configuration setting
    bool islong = false;
    bool isinvalid = true;
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Instrument Initialization:  The instrument tuning is done as early as
            // possible, the load calibration as late as possible
            //
            HIFIInitObs();
            TuneHIFI(band,runningfreq,hrs1,hrs2,wbs1{0},wbs2{0},target);
            delay(tinitslew - (time() - startobs) - loadlength + shiftlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            SScanLoadMeasurement(band,runningfreq,reffreq,true,eff_resolution{0},load_datatime,backendreadoutparms);
            if(shiftlength > 0) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            i_phase = (state[2] + 1) % 2;
            // Reset group counter
            i_group = 0;
            runintostate = false;
            // long integrations not possible in last and first nod cycle
            if(n_cycles > 1 && state[2] % n_cycles != state[2] % 2) {
                if(isinvalid || !islong) {
                    choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_long,band,reffreq,backendreadoutparms);
                    islong = true;
                    isinvalid = false;
                }
                HIFIFastChopOnIntegration(data_time,n_long,band,reffreq,choppars,rates);
            } else {
                if(isinvalid || islong) {
                    choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_bchop,band,reffreq,backendreadoutparms);
                    islong = false;
                    isinvalid = false;
                }
                while(i_group < grouplen - 1) {
                    HIFIFastChopOnIntegration(data_time,n_bchop,band,reffreq,choppars,rates);
                    // retune
                    i_group = i_group + 1;
                    runningfreq = freqgrid[grouporder[i_phase][i_group] + i_freqcycles * grouplen];
                    HIFIChangeFreq(band,runningfreq);
                }
                HIFIFastChopOnIntegration(data_time,n_bchop,band,reffreq,choppars,rates);
                // Now we switch to the next frequency group or repeat the cycle
                if(state[2] % n_cycles == 0 && i_phase == 1) {
                    // Big tuning step, but not at end of observation
                    if(state[2] < allsteps) {
                        i_freqcycles = i_freqcycles + 1;
                        runningfreq = freqgrid[grouporder[0][0] + i_freqcycles * grouplen];
                        target = targetnames[i_freqcycles];
                        HIFIRetuneFreq(band,runningfreq,target);
                        runintostate = true;
                    }
                }
            }
            // Active WBS HK if we have a nod slew without calibration
            if(state[2] % 2 == 1 && state[2] % n_loadinterval > 0) {
                HIFIActiveHK("normal",tnodslew);
            }
        }
        if(state[0] == 7) {
            // second nod position
            i_phase = state[2] % 2;
            // First nodding position
            // Reset group counter
            i_group = 0;
            runintostate = false;
            // long integrations not possible in last and first nod cycle
            if(n_cycles > 1 && state[2] % n_cycles != (state[2] % 2 + 1) % 2) {
                if(isinvalid || !islong) {
                    choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_long,band,reffreq,backendreadoutparms);
                    islong = true;
                    isinvalid = false;
                }
                HIFIFastChopOffIntegration(data_time,n_long,band,reffreq,choppars,rates);
            } else {
                if(isinvalid || islong) {
                    choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_bchop,band,reffreq,backendreadoutparms);
                    islong = false;
                    isinvalid = false;
                }
                while(i_group < grouplen - 1) {
                    HIFIFastChopOffIntegration(data_time,n_bchop,band,reffreq,choppars,rates);
                    // retune
                    i_group = i_group + 1;
                    runningfreq = freqgrid[grouporder[i_phase][i_group] + i_freqcycles * grouplen];
                    HIFIChangeFreq(band,runningfreq);
                }
                HIFIFastChopOffIntegration(data_time,n_bchop,band,reffreq,choppars,rates);
                // Now we switch to the next frequency group or repeat the cycle
                if(state[2] % n_cycles == 0 && i_phase == 1) {
                    // Big tuning step, but not at end of observation
                    if(state[2] < allsteps) {
                        i_freqcycles = i_freqcycles + 1;
                        runningfreq = freqgrid[grouporder[0][0] + i_freqcycles * grouplen];
                        target = targetnames[i_freqcycles];
                        HIFIRetuneFreq(band,runningfreq,target);
                        runintostate = true;
                    }
                }
            }
            // Active WBS HK if we have a nod slew without calibration
            if(state[2] % 2 == 0 && state[2] % n_loadinterval > 0) {
                HIFIActiveHK("normal",tnodslew);
            }
        }
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            SScanLoadMeasurement(band,runningfreq,reffreq,retuneload,eff_resolution{0},load_datatime,backendreadoutparms);
            isinvalid = true;
            runintostate = false;
        }
        if(state[0] == 5) {
            // The instrument stops halftunelength before the telescope
            // but I have to wait to close the observation
            HIFICloseObs();
        }
    }
}

//Set LCU5a back to standby status, procedure
procedure LCU5a_standby_proc_fm {
    string band = "5a"; // HIFI band
    double lo_freq = 1150.0 in [1127.0,1178.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

//LO disable in manual commanding
mode HifiManCmd_LO_disable {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    mois_comment("Procedure to disable the LOU S/S");
    StartMode_block_ops();
    //
    mois_step("Disable LOU");
    LCU_disable_all_bands_block_fm();
    //
    StopMode_block_ops();
    // -> to issue last obsd/bbid
}

//HIFI LO tuning only for M1 and M2 investigation in 7b, block
//Target current is read from look-up table
block LO_tuning_w_M1M2_block_fm HIFI 3718 {
    string band = "7b"; // HIFI band
    double lo_freq = 1890.0; //LO frequency
    double m1 = -5.0; //M1 multiplier voltage
    double m2 = -11.0; //M2 multiplier voltage
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    string mixer_polarization = result[0]{1};
    //
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = m1;
    //result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    //The automatic tuning shall use the min of the nominal best-guess and Vd2max - 100mV
    double middle_d2 = min(result[0]{0},drain2_bluemax - 0.1);
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * middle_d2;
    //drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    if(band == "3b") {
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum);
        //Send command: specific to M3 in 3b
        delay(config_lo_delay);
        //
        //Additional read of TM pages
        LCU_Read_TM_pages_proc_fm();
    } else {
        //
        //General command
        HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    }
    //
    //delay(5);	//to settle at this value
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The blocks
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Diplexer scan, fast, block.
// Mixer current as function of diplexer current. Takes 1 seconds per point
// IT IS THE OBSOLETE VERSION NOT MAKING USE OF THE DEDICATED OBS TC
block Diplexer_scan_fast_fm HIFI 3251 {
    string band = "3a"; // HIFI band
    double diplexer_current_min_h = -2.24; //minimum diplexer current H
    double diplexer_current_max_h = 2.24; //maximum diplexer current H
    double diplexer_current_min_v = -2.24; //minimum diplexer current V
    double diplexer_current_max_v = 2.24; //maximum diplexer current V
    int n_steps = 100; //number of steps
}{
    Start_block();
    int steps = 0;
    int steps_done = 0;
    int steps_wanted = n_steps;
    if(steps_wanted < 1) {
        steps_wanted = 1;
    }
    double diplexer_current_h = 0.0;
    double diplexer_current_v = 0.0;
    double stepsize_h = 0.0;
    double stepsize_v = 0.0;
    //
    if(steps_wanted > 1) {
        stepsize_h = (diplexer_current_max_h - diplexer_current_min_h) / (double(steps_wanted) - 1.0);
        stepsize_v = (diplexer_current_max_v - diplexer_current_min_v) / (double(steps_wanted) - 1.0);
    }
    while(steps_done < steps_wanted) {
        steps = steps_wanted - steps_done;
        if(steps > n_steps) {
            steps = n_steps;
        }
        diplexer_current_h = diplexer_current_min_h + double(steps_done) * stepsize_h;
        Hifi_HIFI_CH1_DPACT_C($BBID,diplexer_current_h);
        //Sets H diplexer current
        diplexer_current_v = diplexer_current_min_v + double(steps_done) * stepsize_v;
        Hifi_HIFI_CV1_DPACT_C($BBID,diplexer_current_v);
        //Sets V diplexer current
        //
        delay(1);
        steps_done = steps_done + 1;
    }
}

// HRS linearity check, loop on individual attenuators, mode
// This is the COP version where no WBS is considered
// =======================================================
block HRS_linearity_indiv_block_cop HIFI 3960 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //Fetch resistive bias
    {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_high_resistive_h","bias_high_resistive_v","bias_medium_resistive_h","bias_medium_resistive_v"],band,0.0);
    //
    double bias_high_h = result[0]{0};
    double bias_high_v = result[1]{0};
    double bias_medium_h = result[2]{0};
    double bias_medium_v = result[3]{0};
    int repeats = 32;
    double hrsH_attenuators_value = 15.5;
    double hrsV_attenuators_value = 15.5;
    //Test will be done in WB mode for both polar
    string hrsh_blocks_configuration = "corr_wide";
    string hrsv_blocks_configuration = "corr_wide";
    // Configure spectroscopy
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    // Configure blocks
    //=================
    //H-polar
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration);
    // 
    //delay(1);
    //V-polar
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration);
    // 
    delay(1);
    // Fetch internal LO settings
    //===========================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    double[] hrsH_LO = [result[1]{0},result[2]{0},result[3]{0},result[4]{0},result[5]{0},result[6]{0},result[7]{0}];
    string hrs_polarization_h = result[0]{1};
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    double[] hrsV_LO = [result[1]{0},result[2]{0},result[3]{0},result[4]{0},result[5]{0},result[6]{0},result[7]{0}];
    string hrs_polarization_v = result[0]{1};
    //
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    //
    ///////////////////////////////////////
    //
    // Loops on the different configurations of the HRS attenuators
    //===============================================
    //Magnets shall be set to 0 since high biases will be used
    Set_Magnet_current_proc_fm(0.0,0.0);
    //
    for(int i = 0 .. repeats - 1) {
        // Configure attenuators and LO
        //=============================
        Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
        // 
        //delay(2);
        Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsH_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
        // 
        delay(1);
        //
        //Set the shot noise to high resistive bias
        Mixerbias(bias_high_h,bias_high_v);
        // Take spectrum
        //==============
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
        //
        //Set the shot noise to medium resistive bias
        Mixerbias(bias_medium_h,bias_medium_v);
        // Take spectrum
        //==============
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
        // Change the value of the 8 attenuators
        //======================================
        hrsH_attenuators_value = hrsH_attenuators_value - 0.5;
        hrsV_attenuators_value = hrsV_attenuators_value - 0.5;
    }
    //
}

// Compute the integration time required on the thermal loads
int procedure LoadIntegrationTime {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    double deltanu = 1.0; // minimum effective resolution of the calibrated data
}{
    // get load temperatures
    {double,double} loadtemp = LoadTemperatures(band,lo_freq);
    double t_hot = loadtemp{0};
    double t_cold = loadtemp{1};
    double t_sys = InterpolateTsys(band,lo_freq);
    // compare to load period
    int loadperiod = LoadPeriod(band,lo_freq,deltanu);
    // exception handling for zero frequency resolutions
    if(deltanu < 0.01) {
        int intload = loadperiod / 8;
    } else {
        // estimator equation guaranteeing only 1% error from load calibration
        double tload = 0.01 / deltanu * ((t_hot + t_sys) * (t_hot + t_sys) + (t_cold + t_sys) * (t_cold + t_sys)) / ((t_hot - t_cold) * (t_hot - t_cold));
        intload = iceil(tload);
        // never exceed half of the load period, even for FSwitch
        intload = imin(intload,loadperiod / 8);
    }

    return intload;
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double,double,double} procedure SScanDoubleChop_deadtimes {
    string chopmode = "chop" in ["chop","lchop","fs"]; // chop mode
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int grouplen = 1; // Number of frequency steps per nodding phase
    int data_time = 4; // data dump interval on ON
    int data_time_off = 4; // data dump interval on OFF
    int n_chop_on = 3; // number of chop cycles in one integration on ON
    int n_chop_off = 3; // number of chop cycles in one integration on OFF
    int n_long_on = 3; // number of chop cycles for long integration on ON
    int n_long_off = 3; // number of chop cycles for long integration on OFF
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    double avnumchop_on = 1.0; // Average number of ON chop cycles per frequency
    double avnumchop_off = 1.0; // Average number of OFF chop cycles per frequency
    double tscan = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Compute parameters for the instrument timing in normal phases
    // Four different cases involved
    {double,double} tinst = GetInstDeadSlowChop(data_time,2 * n_chop_on,chopmode,band,lo_freq,backendreadoutparms);
    // dead time
    double tdeadint_on = double(data_time * 2 * n_chop_on) - tinst{0};
    // subtract dead times in switches
    // keep dead times between A-A and B-B in total dead time
    tdeadint_on = tdeadint_on - double(n_chop_on) * tinst{1};
    // treat integration times of other frequencies as dead time
    double tdeadother = double(data_time * 2 * n_chop_on);
    // Store
    double tswitch_on = tinst{1};
    // Integration time
    double tphaseint_on = tinst{0};
    // Correcton in case of cycles with longer integrations
    if(n_cycles > 1) {
        tinst = GetInstDeadSlowChop(data_time,2 * n_long_on,chopmode,band,lo_freq,backendreadoutparms);
        // dead time
        double tdeadlong = double(data_time * 2 * n_long_on) - tinst{0};
        // subtract dead times in switches
        tdeadlong = tdeadlong - double(n_long_on) * tinst{1};
        // weigh
        int numlong_on = 2 * (n_cycles / 2);
        double wlong = double(numlong_on) / double(grouplen * n_cycles);
        double wshort = double(n_cycles * grouplen - numlong_on) / double(grouplen * n_cycles);
        tdeadint_on = wlong * tdeadlong + wshort * tdeadint_on;
        tphaseint_on = (wlong * tinst{0} + wshort * tphaseint_on) / (2.0 * avnumchop_on);
        tdeadother = wshort * tdeadother + double(data_time * 2 * n_long_on) * wlong;
    } else {
        tphaseint_on = tphaseint_on / (2.0 * avnumchop_on);
    }
    // OFF phase
    tinst = GetInstDeadSlowChop(data_time_off,2 * n_chop_off,chopmode,band,lo_freq,backendreadoutparms);
    // dead time
    double tdeadint_off = double(data_time_off * 2 * n_chop_off) - tinst{0};
    // subtract dead times in switches
    // keep dead times between A-A and B-B in total dead time
    tdeadint_off = tdeadint_off - double(n_chop_off) * tinst{1};
    // Store
    double tswitch_off = tinst{1};
    // Integration time
    double tphaseint_off = tinst{0};
    // Correcton in case of cycles with longer integrations
    if(n_cycles > 1) {
        tinst = GetInstDeadSlowChop(data_time_off,2 * n_long_off,chopmode,band,lo_freq,backendreadoutparms);
        // dead time
        tdeadlong = double(data_time_off * 2 * n_long_off) - tinst{0};
        // subtract dead times in switches
        tdeadlong = tdeadlong - double(n_long_off) * tinst{1};
        // weigh
        int numlong_off = 2 * ((n_cycles - 1) / 2);
        wlong = double(numlong_off) / double(n_cycles);
        wshort = double(n_cycles - numlong_off) / double(n_cycles);
        tdeadint_off = wlong * tdeadlong + wshort * tdeadint_off;
        tphaseint_off = (wlong * tinst{0} + wshort * tphaseint_off) / (2.0 * avnumchop_off);
    } else {
        tphaseint_off = tphaseint_off / (2.0 * avnumchop_off);
    }
    // Total dead time per cycle
    double tdead = tscan - double(grouplen * 2 * data_time) * avnumchop_on - double(2 * data_time_off) * avnumchop_off;
    double tdead_tot = tdead + double(grouplen) * tdeadint_on + tdeadint_off;
    // Add integration times of other frequencies as dead time
    tdead_tot = tdead_tot + double(grouplen - 1) * tdeadother;
    // Return total dead time and the dead times in the two chops

    return {tdead_tot,tphaseint_on,tphaseint_off,tswitch_on,tswitch_off};
}

/////////////////////////////////////////////////////////////////
// Procedure to derive the backend settings for spectral scans
{{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} procedure SScanBackendSettings {
    string band = "4a"; // HIFI band
    int redundancy = 4; // Frequency scan redundancy
    bool wbs1_used = true; // whether WBS1  is used
    bool wbs2_used = true; // whether WBS2  is used
    int data_time = 4; // data dump interval 
}{
    // Standard configuration of the backends
    {bool,int[][]} wbs1 = {wbs1_used,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {wbs2_used,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // WBS parameters ={used, channel windows}
    // Check whether we can use the HRS in parallel
    // Get fixed HRS parameters
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]}} hrsparms = GetSpectralScanHRS(redundancy,band);
    {bool,int,double[],bool[]} hrs1 = hrsparms{0};
    {bool,int,double[],bool[]} hrs2 = hrsparms{1};
    string[] resolstring = ["high-resolution","nominal-resolution","low-resolution","wide-resolution"];
    // Create a composite readout structure
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Compute chunk size given by the data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    // Test whether HRS can be used
    if(dataparms{0} > data_time) {
        // No HRS possible
        // HRS parameters when not used
        hrs1 = {false,1,[-110.0,110.0,0.0,0.0],[false,false,false,false]};
        hrs2 = {false,1,[-110.0,110.0,0.0,0.0],[false,false,false,false]};
        message("No parallel HRS usage due to short chop phase length.<br>");
        // Create a composite readout structure
        backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
        // Check chunk size given by the data rates
        CheckDataTaking(backendreadoutparms,data_time);
    } else {
        message("HRS running parallel in " + resolstring[hrs1{1}] + " mode.<br>");
    }

    return {hrs1,hrs2,wbs1,wbs2};
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure SScanFSwitchNoRef_commanding {
    string band = "4a"; // HIFI band
    double reffreq = 978300.0; // Reference characteristic LO frequency 
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int grouplen = 1; // Number of frequency steps per nodding phase
    int[][] grouporder = [[0],[0]]; // Sequence to trace frequency points in both phases
    double[] freqgrid = [978053.7,978301.8,978381.1]; // Table of frequency points
    bool retuning = false; // need for WBS retuning
    double[] targetlevels = [1.0,1.0,1.0]; // WBS tuning levels
    int data_time = 4; // chunk size
    int n_per_on = 1; // number of half load-sky-sky-load cycles on ON
    int n_load_on = 0; // additional load measurements in ON pointing phase
    int groupnumber = 4; // Total number of frequency groups
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,0]; // Timing of observation from telescope
    int loadlength = 50; // Load duration
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,reffreq,backendreadoutparms);
    // First frequency
    double runningfreq = freqgrid[grouporder[0][0]];
    string[] targetnames = TargetNames(band,reffreq,retuning,targetlevels);
    string target = targetnames[0];
    // All commands with a duration possibly depending on the frequency
    // are taken at the reference frequency to guarantee synchonization
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Instrument Initialization:  The instrument tuning is done as early as
            // possible, the load calibration as late as possible
            //
            HIFIInitObs();
            TuneHIFIFsw(band,runningfreq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},target);
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,true,eff_resolution{0},data_time,backendreadoutparms);
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            for(int i_freq = 0 .. groupnumber - 1) {
                // First frequency
                // Loop over load cycles
                for(int i1 = 1 .. n_load_on) {
                    // Actual measurement
                    HIFIConfigureFSwitchIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                    HIFIFSwitchOnIntegration(data_time,n_per_on,band,reffreq,rates);
                    // Perform load calibration
                    delay(readoutdead);
                    SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,false,eff_resolution{0},data_time,backendreadoutparms);
                }
                if(n_load_on == 0) {
                    // This is the only measurement executed with nload=0
                    HIFIConfigureFSwitchIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                    HIFIFSwitchOnIntegration(data_time,n_per_on,band,reffreq,rates);
                }
                // Other frequencies
                // Reset group counter
                for(int i_group = 1 .. grouplen - 1) {
                    // retune
                    runningfreq = freqgrid[grouporder[0][i_group] + i_freq * grouplen];
                    HIFIChangeFreqFsw(band,runningfreq,freq_throw);
                    if(n_load_on > 0) {
                        // First load
                        SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,false,eff_resolution{0},data_time,backendreadoutparms);
                    } else {
                        // This is the only measurement executed with nload=0
                        HIFIConfigureFSwitchIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                        HIFIFSwitchOnIntegration(data_time,n_per_on,band,reffreq,rates);
                    }
                    // Loop over load cycles
                    for(int i2 = 1 .. n_load_on) {
                        // Actual measurement
                        HIFIConfigureFSwitchIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                        HIFIFSwitchOnIntegration(data_time,n_per_on,band,reffreq,rates);
                        // Perform load calibration
                        delay(readoutdead);
                        SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,false,eff_resolution{0},data_time,backendreadoutparms);
                    }
                }
                // Now we switch to the next frequency group or repeat the cycle
                // Big tuning step, but not at end of observation
                if(i_freq < groupnumber - 1) {
                    runningfreq = freqgrid[grouporder[0][0] + (i_freq + 1) * grouplen];
                    target = targetnames[i_freq + 1];
                    HIFIRetuneFsw(band,runningfreq,freq_throw,target);
                    // first load or main load for n_load=0
                    SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,false,eff_resolution{0},data_time,backendreadoutparms);
                }
            }
        }
        if(state[0] == 5) {
            if(n_load_on == 0) {
                delay(readoutdead);
            }
            HIFICloseObs();
        }
    }
}

{int,double,double,double,double,double} obs HifiPointModeFSwitchNoRef {
    string modeName = "fs";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_cycles = 2 in [1,3600]; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Single Point - Frequency Switch noRef",{data_time,0,0,0,0,0,0,0,n_cycles,load_interval});
    // Two cases: fine pointing or position switch
    // Call first part of the timing computer
    {int,int,int,int,int,int,bool,int,int} pre_timing_f = FSwitchNoRef_pre_timing(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_cycles,load_interval,docommands);
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,double,double,int} tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,pre_timing_f);
    // Dummy call to spacecraft command
    int[] telescopetimes = basic_fine_pointing(false,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,bool,int,int},double,double} post_timing_f = SingleChopNoRef_post_timing(pre_timing_f,telescopetimes);
    // Now the actual observation starts
    // Prepare telescope command
    tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,post_timing_f{1});
    // Call telescope command 
    telescopetimes = basic_fine_pointing(true,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
    // Consistency check
    int totaltime = post_timing_f{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    //////////////////////////////////////////////////////////////////////
    // standard parameters for fine pointing
    int loadlength = post_timing_f{1}{2};
    int n_per_on = post_timing_f{1}{4};
    int n_load_on = post_timing_f{1}{5};
    bool end_load_on = post_timing_f{1}{6};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    //////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FSwitchNoRef_commanding(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_per_on,n_load_on,end_load_on,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SingleChop_deadtimes("fs",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_per_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = FSwitchNoRef_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_per_on * (n_load_on + 1),tscan,tdead);
    // Evaluate performance
    SingleChopNoRef_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_per_on * (n_load_on + 1),true,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Vector scan calibration for a given LO band
// Ues domains of frequencies to be scanned for each LO sub-band
procedure Vecscan_calibration_proc_fm_COP {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //
    LCU_switchon_proc_fm(band);
    //Wait an extra delay of 1 min for short term stabilization
    delay(60);
    //
    //Get the list of frequencies to be used for the scan
    string tab = "config_vecscan.config";
    double bandnb = GetBandCode(band);
    double lofreqlow = dlookup(tab,"" + iceil(bandnb),"lofreqlow");
    double lofreqhigh = dlookup(tab,"" + iceil(bandnb),"lofreqhigh");
    double lofreqstep = dlookup(tab,"" + iceil(bandnb),"lofreqstep");
    //
    double current_LO = lofreqlow;
    bool endreached = false;
    //Loop on key frequencies per LO band
    while(current_LO <= lofreqhigh && endreached == false) {
        //Configure FPU at that frequency
        //SPR-2463: look at HBB
        Init_MSA_HBB_fm(band,"CLOSE",current_LO,"ON");
        //
        //Perform vector scan within BLUE limits at that frequency
        Vector_scan_BLUE_LIMIT_block_fm(band,current_LO);
        //LCU_CLEAR_ERROR_block_fm();
        //
        //sanity check
        //double[] result_dip = Get_Diplexer_setting(band,current_LO);
        //message("LO freq " + current_LO + " " + result_dip[0] + " " + result_dip[1]);
        //Check last LO freq done
        if(current_LO == lofreqhigh && endreached == false) {
            endreached = true;
        }
        //Increase LO freq: truncate if step too high
        current_LO = current_LO + lofreqstep;
        if(current_LO > lofreqhigh && endreached == false) {
            current_LO = lofreqhigh;
        }
    }
    //
}

/////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing for a
// Spectral Scan Frequency-Switch observing mode
// 
{{int,int,int,int,int,int,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} procedure SScanFSwitchNoRef_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq_low = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4; // Frequency scan redundancy
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_chop_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Create composite readout structure for backends
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get frequency grid characteristic parameters
    {int,double,double[],int[][],int,bool} fqparms = MakeFreqGrid(band,lo_freq_low,lo_freq_up,redundancy,freq_throw,n_freq_point);
    int groupnumber = fqparms{0};
    double reffreq = fqparms{1};
    double[] freqgrid = fqparms{2};
    int[][] grouporder = fqparms{3};
    // Process tuning level grid
    double[][] levelgrid = GetSScanLevelGrid(band,wbs1,wbs2,freqgrid,fqparms{0},grouporder);
    {bool,double[]} targets = TargetLevels(band,reffreq,levelgrid);
    bool retuning = targets{0};
    double[] targetgrid = targets{1};
    string reftarget = "";
    if(retuning) {
        reftarget = "sscan_normal";
    }
    {int,double,double[],int[][],bool,double[],int,bool} spectralparms = {fqparms{0},reffreq,freqgrid,grouporder,retuning,targetgrid,fqparms{4},fqparms{5}};
    //////////////////////////////////////////////////////////////////////
    // Get timing within the normal frequency-switch observations
    int readoutdead = SlowChopReadoutDelay(band,reffreq,backendreadoutparms);
    int jitterdead = GetMaxTimeJitter(band,reffreq);
    // Integration time per frequency and pointing
    int on_inttime = 2 * n_chop_on * data_time;
    // Tuning delays
    int bigtunestep = duration(HIFIRetuneFsw(band,reffreq,freq_throw,reftarget));
    // Correct for variation within the band
    int tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq);
    bigtunestep = bigtunestep + 2 * tunediff;
    // A step within a group could be faster than a large step
    if(n_freq_point > 1) {
        int smallstep = duration(HIFIChangeFreqFsw(band,reffreq,freq_throw));
    } else {
        smallstep = bigtunestep;
    }
    int grouptime = n_freq_point * on_inttime + (n_freq_point - 1) * smallstep;
    // Duration of initial set up
    // Staying at the same frequency makes no sense here. 
    // First frequency point
    double runningfreq = freqgrid[grouporder[0][0]];
    // Compute load integration time
    int loadlength = duration(SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,true,eff_resolution{0},data_time,backendreadoutparms));
    loadlength = loadlength + readoutdead;
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFIFsw(band,runningfreq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},"sscan_normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,runningfreq,true);
    }
    initlength = initlength + loadlength;
    int initloadlength = loadlength;
    // recompute load length during slews  - no retuning
    loadlength = duration(SScanDoubleLoadMeasurement(band,reffreq,reffreq,freq_throw,false,eff_resolution{0},data_time,backendreadoutparms));
    loadlength = loadlength + readoutdead;
    // Compare load interval with duration of the observation
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    if(load_spacing < grouptime && n_freq_point > 1) {
        SError("Load period too short for frequency group size.");
    }
    // Here we bracket each cycle by loads, this leads to a grace period
    int n_load_on = on_inttime / load_spacing;
    // In the following the definition of n_load_on is higher by 1 relative to 
    // that used in normal frequency switch!
    // This determines the order of the loops
    if(n_load_on == 0) {
        int n_per_on = n_chop_on;
        bool end_load_on = false;
    } else {
        // grace condition
        if(double(on_inttime) > 1.2 * double(load_spacing)) {
            n_load_on = n_load_on + 1;
        }
        n_per_on = n_chop_on / n_load_on;
        if(n_per_on < 1) {
            SError("FS phase length on source too long relative to load period.");
        }
        end_load_on = true;
        on_inttime = 2 * n_per_on * n_load_on * data_time;
        // This cannot happen for n_freq_point > 1
        grouptime = on_inttime + n_load_on * loadlength;
    }
    int on_pointing = groupnumber * (grouptime + bigtunestep + loadlength) - bigtunestep - loadlength + jitterdead;
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed for telescope call and post_timing processing

    return {{on_inttime,on_pointing,initloadlength,load_spacing,n_per_on,n_load_on,end_load_on,initlength,dangling},spectralparms};
}

////////////////////////////////////////
// Standing wave on the Imix
//  no-spectra version
procedure Standing_wave_nospectra_fm_COP {
    string band = "1a"; // HIFI band
    double[] lo_freq_input = [500.0,500.15,0.02]; //Start, end and step lo_freq for the LO scan
}{
    // Initial LO tuning at centre frequency of scan
    //
    double lo_freq_ref = (lo_freq_input[0] + lo_freq_input[1]) / 2.0;
    LO_tuning_block_fm(band,lo_freq_ref);
    double lo_freq = lo_freq_input[0];
    //Loop on LO frequencies. It is assumed that the LO is tuned at the middle frequency of the scan
    //
    int nbstep = 0;
    //For freq above 1THz rounding makes miss the last step.
    double margin = 0.1 / 1.0E9;
    //0.1Hz
    while(lo_freq <= lo_freq_input[1] + margin) {
        //Set synthesizer to new LO freq.
        LCU_config_nominal_noretune_block_fm(band,lo_freq,lo_freq_ref);
        //
        //Increase lo_freq
        lo_freq = lo_freq + lo_freq_input[2];
        nbstep = nbstep + 1;
    }
    message("LO freq: " + lo_freq_ref + "Nb of steps: " + nbstep);
}

// Spectrometer configuration for slow chop, low level procedure
int[] procedure Configure_Spectrometer_slow_chop_proc_fm {
    string band = "1a"; // HIFI band
    int integ_time = 8; //Total integration time in sec. for the two phases !
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Compute data_time and n_switch use the wrapper
    int[] res = ConfigSlowChop(integ_time,"chop",band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_switch = res[1];
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS.
    // The deadtimes output is not used at ILT level.
    {double,double} dtimes = ConfigSpectroscopySlowChop_IST(data_time,n_switch,"chop",band,0.0,backendreadoutparms,true);
    //

    return res;
}

//////////////////////////////////////////////////////////////////////
// Compatibility procedure to provide the same API as used in
// the previous versions
//
// Returns the actual integration time and the dead time per phase
{{double,double,double},{int,int}} procedure ConfigSpectroscopyFastChop_IST {
    /* Integration time */
    double data_chop = 0.5 in [0.1,2.0]; // Length of a single chop phase
    int n_int = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string band = "1a"; // HIFI band
    double lo_freq = 522000.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used,channel windows} 
}{
    // Translate data_chop into new parameter data_time (approximate)
    // Get auxiliary quantities
    {double,string}[] result = ConfigurationReader("name_delays",["add_wbs","add_jitter","wbs_readout","wbs_init"],band,lo_freq);
    int add_wbs = iround(result[0]{0});
    int add_jitter = iround(result[1]{0});
    int wbs_readout = iround(result[2]{0});
    int wbs_init = iround(result[3]{0});
    int tdead_data = 2 * (wbs_readout + add_jitter) + add_wbs - add_jitter;
    int totaltime = (iceil(1000.0 * data_chop) * 2 * n_int + tdead_data) * n_data + wbs_init;
    totaltime = iceil(double(totaltime) / 1000.0);
    int data_time = (totaltime + n_data - 1) / n_data;
    // Check
    CheckFastChopFrequency(band,lo_freq,data_time,n_int,n_data);
    // Get timing parameters
    bool wbs_used = backendreadoutparms{2}{0} || backendreadoutparms{3}{0};
    {int,int,int,int,int,int,int,int,int,int,int,int,int} timing = FastConfigureSpectroscopyParams_IST(data_time,n_int,n_data,band,lo_freq,wbs_used);
    int n_wbs_start = timing{0};
    int r_hrs = timing{1};
    int n_wbs_integr = timing{2};
    int n_hrs_integr = timing{3};
    int del_hrs = timing{4};
    int del_wbs = timing{5};
    int t_acc_wbs = timing{6};
    int t_acc_hrs = timing{7};
    int n_wbs1 = timing{8};
    int n_hrs_trans = timing{9};
    int tdead_chop = timing{10};
    tdead_data = timing{11};
    int tint_act = timing{12};
    {int,int,int,int,int[],int[],string} backendconfigure = ConfigSpectroscopyBackends(data_time,backendreadoutparms);
    int wbs_rshift = backendconfigure{0};
    int hrs_rshift = backendconfigure{1};
    int hrsh_sel = backendconfigure{2};
    int hrsv_sel = backendconfigure{3};
    int[] wbsh_par = backendconfigure{4};
    int[] wbsv_par = backendconfigure{5};
    string packing = backendconfigure{6};
    // Now call the command
    Hifi_HIFI_config_spectroscopy($BBID,n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,wbsh_par[0],wbsh_par[1],wbsh_par[2],wbsh_par[3],wbsh_par[4],wbsh_par[5],wbsh_par[6],wbsh_par[7],wbsv_par[0],wbsv_par[1],wbsv_par[2],wbsv_par[3],wbsv_par[4],wbsv_par[5],wbsv_par[6],wbsv_par[7],hrs_rshift,wbs_rshift,hrsh_sel,hrsv_sel,packing);
    //
    // Return dead times and comand parameters

    return {{double(tint_act) / 1000.0,double(tdead_chop) / 1000.0,double(data_time * n_data)},{n_wbs1,n_hrs_trans}};
}

//HIFI-COP-3-Stab-1
//This one should be use for preparation via XHSpot
//It assumes one obsid per band/stab_category/freq
obs HifiEng_Stab_COP {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string stab = "sys" in ["sys","lsw","int","dbs","fsw","stab"]; //category of stability measurement
    int freq_index = 1; //Frequency index to be applied
    int throw_index = 1; //FSW throw index to be applied
}{
    //General parameters in use
    string[] hrs_mode = ["wb1","wb1"];
    int integ_time = 4;
    double chop_phase = 1.0;
    string shutter = "open";
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Stab_COP_proc_ops(band,stab,freq_index,throw_index,hrs_mode,integ_time,chop_phase,shutter));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Stab_COP_proc_ops(band,stab,freq_index,throw_index,hrs_mode,integ_time,chop_phase,shutter);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

{string,double,double}[] procedure HifiPointModeLoadChopSequencerInit {
    string modeName = "load";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half load-sky-sky-load cycles on ON
    int n_switch_off = 2 in [1,900]; // number of half load-sky-sky-load cycles on OFF
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF calibration cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    {double,double,double,double} phaselengths = LoadChopPhaseLengths(band,lo_freq,effResolution,oneGHzReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_switch_on_guess = imax(iceil(phaselengths{0} / (2.0 * double(data_time_guess))),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,2 * n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    new_data_time = MatchMinPointing(data_time_off_guess,data_time_off_range,2 * n_switch_off_guess);
    data_time_off_guess = new_data_time{0};
    data_time_off_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)}];

    return retvalues;
}

// Procedure to get timing in a spectroscopy measurement
{double,double} procedure GetInstDeadSlowChop {
    /* Integration time */
    int data_time = 4; // Integration time between two data readouts
    int n_int = 2; // Integration time counter
    string chopmode = "chop" in ["chop","lchop","fs","hot-cold","tp"]; // Chop mode determining the modulation dead time
    /* Parameters determining the delays - used in calibration reader */
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used,channel windows}
}{
    // Get timing parameters
    {int,int,int,int,int,int,int,int,int,int} timing = ConfigureSpectroscopyParams(data_time,n_int,chopmode,band,lo_freq,backendreadoutparms);
    int tdead = timing{8};
    int tint = timing{9};
    // Return dead time per full integration
    double tintall = double(tint) / 1000.0;
    double tdeadphase = double(tdead) / 1000.0;

    return {tintall,tdeadphase};
}

// Combine radiometric and drift noise from an OTF observation
// Normalized to mapping without overhead
// 
{double,double} procedure OtfNoiseValues {
    double n = 10.0; // number of points in one scan
    double[] parameters = [0.02,0.4,0.05,0.667,2.5]; // Parameters: integration time, delay, slew from OFF relative to Allan time, ratio of t_off time to sqrt(n)*t_on, drift exponent
}{
    // Assign parameters
    double npoints = double(ifloor(n));
    double x = parameters[0];
    double d = parameters[1];
    double doff = parameters[2];
    double qval = parameters[3];
    double alpha = parameters[4];
    if(npoints > 0.0) {
        // OFF integration time
        double xr = qval * sqrt(npoints) * x;
        // Total delay
        double dtot = (npoints - 1.0) * x + d;
        // Try two points at the edge and the center of a scan to get the extremes
        double[] pp = [0.0,0.5];
        double[] yn = [0.0,0.5];
        double[] yd = [0.0,0.5];
        double[] yy = [0.0,0.5];
        double p = 0.0;
        for(int ip = 0 .. 1) {
            p = pp[ip];
            // Delay length before measured point
            double d1 = doff + double(ifloor(p * npoints)) * x + p * (d - 2.0 * doff);
            // Remaining delay
            double d2 = dtot - d1;
            // add radiometric and drift noise
            yn[ip] = OtfRadioNoise(x,xr,d1,d2);
            yd[ip] = OtfDrift(x,xr,d1,d2,alpha);
            yy[ip] = yn[ip] + yd[ip];
        }
        // Normalization - relative to mapping without overhead
        double norm = (x + xr + dtot) / npoints;
        // Get worst case
        if(yy[0] > yy[1]) {
            double ynm = yn[0] * norm;
            double ydm = yd[0] * norm;
        } else {
            ynm = yn[1] * norm;
            ydm = yd[1] * norm;
        }
        // Artificially forbid OTF scans much longer than the Allan time
        double driftadd = max(dtot + x - 10.0,0.0) * 0.1;
        ydm = ydm + driftadd * ynm;
    } else {
        // forbid negative point numbers
        ynm = 1.0E11;
        ydm = 1.0E11;
    }

    return {ynm,ydm};
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure SScanLoadChopNoRef_commanding {
    string band = "4a"; // HIFI band
    double reffreq = 978300.0; // Reference characteristic LO frequency 
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int grouplen = 1; // Number of frequency steps per nodding phase
    int[][] grouporder = [[0],[0]]; // Sequence to trace frequency points in both phases
    double[] freqgrid = [978053.7,978301.8,978381.1]; // Table of frequency points
    bool retuning = false; // need for WBS retuning
    double[] targetlevels = [1.0,1.0,1.0]; // WBS tuning levels
    int data_time = 4; // chunk size
    int n_per_on = 1; // number of half load-sky-sky-load cycles on ON
    int n_load_on = 0; // additional load measurements in ON pointing phase
    int groupnumber = 4; // Total number of frequency groups
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,0]; // Timing of observation from telescope
    int loadlength = 50; // Load duration
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,reffreq,backendreadoutparms);
    bool retuneload = n_load_on > 0;
    // First frequency
    double runningfreq = freqgrid[grouporder[0][0]];
    string[] targetnames = TargetNames(band,reffreq,retuning,targetlevels);
    string target = targetnames[0];
    // All commands with a duration possibly depending on the frequency
    // are taken at the reference frequency to guarantee synchonization
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Instrument Initialization:  The instrument tuning is done as early as
            // possible, the load calibration as late as possible
            //
            HIFIInitObs();
            TuneHIFI(band,runningfreq,hrs1,hrs2,wbs1{0},wbs2{0},target);
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            SScanLoadMeasurement(band,runningfreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms);
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            for(int i_freq = 0 .. groupnumber - 1) {
                // First frequency
                // Loop over load cycles
                for(int i1 = 1 .. n_load_on) {
                    // Actual measurement
                    HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                    HIFILoadChopOnIntegration(data_time,n_per_on,band,reffreq,rates);
                    // Perform load calibration
                    delay(readoutdead);
                    SScanLoadMeasurement(band,runningfreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms);
                }
                if(n_load_on == 0) {
                    // This is the only measurement executed with nload=0
                    HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                    HIFILoadChopOnIntegration(data_time,n_per_on,band,reffreq,rates);
                }
                // Other frequencies
                // Reset group counter
                for(int i_group = 1 .. grouplen - 1) {
                    // retune
                    runningfreq = freqgrid[grouporder[0][i_group] + i_freq * grouplen];
                    HIFIChangeFreq(band,runningfreq);
                    if(retuneload) {
                        // First load
                        SScanLoadMeasurement(band,runningfreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms);
                    } else {
                        // This is the only measurement executed with nload=0
                        HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                        HIFILoadChopOnIntegration(data_time,n_per_on,band,reffreq,rates);
                    }
                    // Loop over load cycles
                    for(int i2 = 1 .. n_load_on) {
                        // Actual measurement
                        HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                        HIFILoadChopOnIntegration(data_time,n_per_on,band,reffreq,rates);
                        // Perform load calibration
                        delay(readoutdead);
                        SScanLoadMeasurement(band,runningfreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms);
                    }
                }
                // Now we switch to the next frequency group or repeat the cycle
                // Big tuning step, but not at end of observation
                if(i_freq < groupnumber - 1) {
                    runningfreq = freqgrid[grouporder[0][0] + (i_freq + 1) * grouplen];
                    target = targetnames[i_freq + 1];
                    HIFIRetuneFreq(band,runningfreq,target);
                    // first load or main load for n_load=0
                    SScanLoadMeasurement(band,runningfreq,reffreq,retuneload,eff_resolution{0},data_time,backendreadoutparms);
                }
            }
        }
        if(state[0] == 5) {
            if(n_load_on == 0) {
                delay(readoutdead);
            }
            HIFICloseObs();
        }
    }
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The procedures
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Mode initialisation
procedure StartMode {
}{
    BroadcastOBSID();
    //Get applicable HK rate
    {double,string}[] result_d = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    double hk_rate = result_d[0]{0};
    HKrate(hk_rate);
}

// BLOCK : Functional Test No 1 (HRS Master Reset)
block HRS_functional_test_No_1_block_fm HIFI 3611 {
}{
    //Start_block();
    //
    //Use new command implemented in SCR-859
    Hifi_HIFI_HRS_functional_test($BBID,1,"BOTH");
    delay(5);
    //
}

// Total noise from an asymmetric double difference observation
// This is still to be scaled by a factor 1.0/(B_fluct*T_obs)
double procedure DoubleDifferenceNoise {
    double x = 0.1; // value for integration time relative to Allan time
    double[] parameters = [1.0,1.0,0.8,0.8,0.05,0.3,2.5,5.0,2.5]; // Parameters: ratio of integration times, ratio of effective resolutions, delay in phase1, in phase 2, between phases relative to Allan time, drift exponents 
}{
    // Assign parameters
    double tpa = parameters[2];
    // total length of A pointing phase
    double tpb = parameters[3];
    // total length of B pointing phase
    double d = parameters[5];
    // position switch dead time relative to differential Allan
    {double,double} noisevalues = DoubleDifferenceNoiseValues(x,parameters);
    // Add and normalize with respect to total observing time
    double y = (noisevalues{0} + noisevalues{1}) * (tpa + tpb + d);

    return y;
}

// Perform load chop integration at OFF position ON-OFF-OFF-ON...
block HIFILoadChopOffIntegration HIFI 6036 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_slow_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_cold","chop_M3"],rates);
}

// Give sequence of frequency steps in a spectral scan mode within one group
double[][] procedure SpreadHRS {
    string band = "4a"; // HIFI band
    int[] resolution = [1,1]; // Frequency resolution
    double[] offset = [0.0,0.0]; // Center offsets
}{
    // Define using the values for resolution=0
    double[][] settings = [[offset[0],0.0,0.0,0.0],[offset[1],0.0,0.0,0.0]];
    // set up individually for the two HRS's
    for(int i = 0 .. 1) {
        int res = resolution[i];
        double off = offset[i];
        // create settings
        if(res == 0) {
            double[] subset = [off,0.0,0.0,0.0];
        } else {
            // Set subband width
            double singlewidth = GetBackendBandwidth(band,0.0,res);
            // Arrange with some overlap
            double hrsgranularity = 20.0;
            double doff = 0.5 * (singlewidth - hrsgranularity);
            if(res == 1) {
                subset = [off - doff,off + doff,0.0,0.0];
            } else {
                subset = [off - 3.0 * doff,off - doff,off + doff,off + 3.0 * doff];
            }
        }
        settings[i] = subset;
    }

    return settings;
}

// Change of HK rate - setting of corresponding data rates
block HIFISetHK HIFI 6001 {
    string speed = "normal" in ["fast","normal","slow"]; // Select HK rate
    bool active = false; // Whether to actively query the spectrometers
}{
    // Get parameters
    {string,int,double,double,double,double} hkparms = PeriodicHKParms(speed);
    non_ess_hk_data_rate(hkparms{3} / 1024.0);
    ess_hk_data_rate(hkparms{5} / 1024.0);
    // Subsystems to be queried
    string[] pattern = QueryHKPattern(active);
    Hifi_HIFI_Housekeeping_on(hkparms{0},pattern[0],pattern[1],pattern[2],pattern[3],pattern[4],pattern[5]);
    delay(1);
}

// Initialisation of FPU, block with both MSA in use
// It is for cold context !
// It can control the diplexer filter
block Init_MSA_DipFilter_fm HIFI 3954 {
    string band = "1a"; // HIFI band
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
    string hbb_heater = "ON" in ["ON","OFF"]; //hot source on/off
    int diplex_h_ctrl_mode = 227; //Diplexer filter
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    //int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = diplex_h_ctrl_mode;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    if(hbb_heater == "ON") {
        result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,lo_freq);
        calibcurrent = result_d[0]{0};
    }
    //
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        //diplex_h_ctrl_mode = iround(result_d[0]{0});
        //diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,0.0);
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //In case of band 6 or 7, bias have been set to 4mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    //Magnet are so far at maximum value. Now set to nominal
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
        Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
        delay(1);
    }
    //
    //Hifi_HIFI_non_periodic_hk_FCU ();
}

//Filler procedure to generate TPF for Spurious tests
//We use a TC that calls only the BBID, pass the currents
//frequency param, and Vd2
//Its value will corrected after IPF generation
procedure COP_Spur_TPF_maker {
    string band = "3b" in ["3b","7b"]; // HIFI band
    int testblock = 1 in [0,3]; //Test block for 3b
}{
    int bbid = 1;
    string name_confindex = "name_confindex_b";
    //We will loop on tabulated frequencies
    //For each we will tune LO power and do diplexer scans
    //for 5-8 M1 settings
    //1. Get the list of frequencies to be used for the scan
    string tab1 = "config_M1calib_" + band + "_" + testblock + ".config";
    if(testblock == 0) {
        tab1 = "config_M1calib_" + band + "_COP.config";
        string tab2 = "config_M2calib_" + band + "_COP.config";
    }
    int total = table_size(tab1);
    double[] freq = [];
    double[] m1_1 = [];
    double[] m1_2 = [];
    double[] m1_3 = [];
    double[] m1_4 = [];
    double[] m1_5 = [];
    double[] m1_6 = [];
    double[] m1_7 = [];
    double[] m1_8 = [];
    double[] m2 = [];
    double[] m3 = [];
    for(int j = 1 .. total) {
        if(band == "7b") {
            freq[j] = dlookup(tab1,"" + j,"frequency");
            m1_1[j] = dlookup(tab1,"" + j,"m1_1");
            m1_2[j] = dlookup(tab1,"" + j,"m1_2");
            m1_3[j] = dlookup(tab1,"" + j,"m1_3");
            m1_4[j] = dlookup(tab1,"" + j,"m1_4");
            m1_5[j] = dlookup(tab1,"" + j,"m1_5");
            //Get frequency parameters
            {double,string}[] result = ConfigurationReader(name_confindex,["freq_nx"],band,freq[j]);
            int freq_nx = ifloor(result[0]{0});
            //Compute lsu_main and offset
            int[] resu = ComputeLSU_A_M_R(band,freq[j]);
            int lsu_main = resu[0];
            int lsu_offset = resu[1];
            //Get max Vd2
            double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,freq[j]);
            //Convert into raw:
            int vd2 = convert_to_raw("hifi_HL_Drain2_7B_V",drain2_bluemax);
            int mm1_1 = convert_to_raw("hifi_HL_M1_7B_V",m1_1[j]);
            int mm1_2 = convert_to_raw("hifi_HL_M1_7B_V",m1_2[j]);
            int mm1_3 = convert_to_raw("hifi_HL_M1_7B_V",m1_3[j]);
            int mm1_4 = convert_to_raw("hifi_HL_M1_7B_V",m1_4[j]);
            int mm1_5 = convert_to_raw("hifi_HL_M1_7B_V",m1_5[j]);
            Hifi_HIFI_WBS_Zero(mm1_1);
            Hifi_HIFI_WBS_Zero(mm1_1);
            Hifi_HIFI_WBS_Zero(mm1_1);
            Hifi_HIFI_WBS_Zero(mm1_2);
            Hifi_HIFI_WBS_Zero(mm1_2);
            Hifi_HIFI_WBS_Zero(mm1_2);
            Hifi_HIFI_WBS_Zero(mm1_3);
            Hifi_HIFI_WBS_Zero(mm1_3);
            Hifi_HIFI_WBS_Zero(mm1_3);
            Hifi_HIFI_WBS_Zero(mm1_4);
            Hifi_HIFI_WBS_Zero(mm1_4);
            Hifi_HIFI_WBS_Zero(mm1_4);
            Hifi_HIFI_WBS_Zero(mm1_5);
            Hifi_HIFI_WBS_Zero(mm1_5);
            Hifi_HIFI_WBS_Zero(mm1_5);
        }
        if(band == "3b") {
            freq[j] = dlookup(tab1,"" + j,"frequency");
            m1_1[j] = dlookup(tab1,"" + j,"m1_1");
            m1_2[j] = dlookup(tab1,"" + j,"m1_2");
            m1_3[j] = dlookup(tab1,"" + j,"m1_3");
            m1_4[j] = dlookup(tab1,"" + j,"m1_4");
            m1_5[j] = dlookup(tab1,"" + j,"m1_5");
            m1_6[j] = dlookup(tab1,"" + j,"m1_6");
            m1_7[j] = dlookup(tab1,"" + j,"m1_7");
            //m1_8[j] = dlookup(tab1,"" + j,"m1_8");
            if(testblock > 0) {
                m2[j] = dlookup(tab1,"" + j,"m2_" + testblock);
                m3[j] = dlookup(tab1,"" + j,"m3_" + testblock);
            } else {
                m2[j] = dlookup(tab2,"" + j,"m2_1");
                m3[j] = dlookup(tab2,"" + j,"m3_1");
            }
            //Get frequency parameters
            result = ConfigurationReader(name_confindex,["freq_nx"],band,freq[j]);
            freq_nx = ifloor(result[0]{0});
            //Compute lsu_main and offset
            resu = ComputeLSU_A_M_R(band,freq[j]);
            lsu_main = resu[0];
            lsu_offset = resu[1];
            //Get gates and drain1
            double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v"],band,freq[j]);
            double gate1_v = cresult[0];
            double gate2_v = cresult[1];
            double drain1_v = cresult[2];
            //Get curlims
            result = ConfigurationReader("name_configlo_b",["curlim1_v","curlim2_v"],band,freq[j]);
            string curlim1 = result[0]{1};
            string curlim2 = result[1]{1};
            //Get max Vd2
            drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,freq[j]);
            //Convert into raw:
            int g1 = convert_to_raw("hifi_HL_Gate1_3B_V",gate1_v);
            int g2 = convert_to_raw("hifi_HL_Gate2_3B_V",gate2_v);
            int vd1 = convert_to_raw("hifi_HL_Drain1_3B_V",drain1_v);
            //convert_to_raw does not work for params defined through TextualCalibrationCurves
            //The convertion is:
            if(curlim1 == "1.5") {
                int curl1 = 0;
            }
            if(curlim1 == "1.4") {
                curl1 = 2;
            }
            if(curlim1 == "1.3") {
                curl1 = 1;
            }
            if(curlim1 == "1.22") {
                curl1 = 3;
            }
            //
            if(curlim2 == "1.5") {
                int curl2 = 0;
            }
            if(curlim2 == "1.4") {
                curl2 = 2;
            }
            if(curlim2 == "1.3") {
                curl2 = 1;
            }
            if(curlim2 == "1.22") {
                curl2 = 3;
            }
            vd2 = convert_to_raw("hifi_HL_Drain2_3B_V",drain2_bluemax);
            mm1_1 = convert_to_raw("hifi_HL_M1_3B_V",m1_1[j]);
            mm1_2 = convert_to_raw("hifi_HL_M1_3B_V",m1_2[j]);
            mm1_3 = convert_to_raw("hifi_HL_M1_3B_V",m1_3[j]);
            mm1_4 = convert_to_raw("hifi_HL_M1_3B_V",m1_4[j]);
            mm1_5 = convert_to_raw("hifi_HL_M1_3B_V",m1_5[j]);
            int mm1_6 = convert_to_raw("hifi_HL_M1_3B_V",m1_6[j]);
            int mm1_7 = convert_to_raw("hifi_HL_M1_3B_V",m1_7[j]);
            //int mm1_8 = convert_to_raw("hifi_HL_M1_3B_V",m1_8[j]);
            int mm2 = convert_to_raw("hifi_HL_M2_3B_V",m2[j]);
            int mm3 = convert_to_raw("hifi_HL_M3_3B_V",m3[j]);
            int mm2_generic = mm2;
            if(testblock == 2) {
                mm2_generic = mm2;
            }
            if(testblock == 3) {
                mm2_generic = mm2;
            }
            //Hifi_HIFI_WBS_Zero(freq_nx);
            //Hifi_HIFI_WBS_Zero(lsu_main);
            //Hifi_HIFI_WBS_Zero(lsu_offset);
            Hifi_HIFI_WBS_Zero(mm1_1);
            Hifi_HIFI_WBS_Zero(mm2_generic);
            Hifi_HIFI_WBS_Zero(mm3);
            Hifi_HIFI_WBS_Zero(g1);
            Hifi_HIFI_WBS_Zero(g2);
            Hifi_HIFI_WBS_Zero(vd1);
            Hifi_HIFI_WBS_Zero(curl1);
            Hifi_HIFI_WBS_Zero(vd2);
            Hifi_HIFI_WBS_Zero(curl2);
            //Hifi_HIFI_WBS_Zero(freq_nx);
            //Hifi_HIFI_WBS_Zero(lsu_main);
            //Hifi_HIFI_WBS_Zero(lsu_offset);
            Hifi_HIFI_WBS_Zero(mm1_2);
            Hifi_HIFI_WBS_Zero(mm2_generic);
            Hifi_HIFI_WBS_Zero(mm3);
            Hifi_HIFI_WBS_Zero(g1);
            Hifi_HIFI_WBS_Zero(g2);
            Hifi_HIFI_WBS_Zero(vd1);
            Hifi_HIFI_WBS_Zero(curl1);
            Hifi_HIFI_WBS_Zero(vd2);
            Hifi_HIFI_WBS_Zero(curl2);
            //Hifi_HIFI_WBS_Zero(freq_nx);
            //Hifi_HIFI_WBS_Zero(lsu_main);
            //Hifi_HIFI_WBS_Zero(lsu_offset);
            Hifi_HIFI_WBS_Zero(mm1_3);
            Hifi_HIFI_WBS_Zero(mm2_generic);
            Hifi_HIFI_WBS_Zero(mm3);
            Hifi_HIFI_WBS_Zero(g1);
            Hifi_HIFI_WBS_Zero(g2);
            Hifi_HIFI_WBS_Zero(vd1);
            Hifi_HIFI_WBS_Zero(curl1);
            Hifi_HIFI_WBS_Zero(vd2);
            Hifi_HIFI_WBS_Zero(curl2);
            //Hifi_HIFI_WBS_Zero(freq_nx);
            //Hifi_HIFI_WBS_Zero(lsu_main);
            //Hifi_HIFI_WBS_Zero(lsu_offset);
            Hifi_HIFI_WBS_Zero(mm1_4);
            Hifi_HIFI_WBS_Zero(mm2_generic);
            Hifi_HIFI_WBS_Zero(mm3);
            Hifi_HIFI_WBS_Zero(g1);
            Hifi_HIFI_WBS_Zero(g2);
            Hifi_HIFI_WBS_Zero(vd1);
            Hifi_HIFI_WBS_Zero(curl1);
            Hifi_HIFI_WBS_Zero(vd2);
            Hifi_HIFI_WBS_Zero(curl2);
            //Hifi_HIFI_WBS_Zero(freq_nx);
            //Hifi_HIFI_WBS_Zero(lsu_main);
            //Hifi_HIFI_WBS_Zero(lsu_offset);
            Hifi_HIFI_WBS_Zero(mm1_5);
            Hifi_HIFI_WBS_Zero(mm2_generic);
            Hifi_HIFI_WBS_Zero(mm3);
            Hifi_HIFI_WBS_Zero(g1);
            Hifi_HIFI_WBS_Zero(g2);
            Hifi_HIFI_WBS_Zero(vd1);
            Hifi_HIFI_WBS_Zero(curl1);
            Hifi_HIFI_WBS_Zero(vd2);
            Hifi_HIFI_WBS_Zero(curl2);
            //Hifi_HIFI_WBS_Zero(freq_nx);
            //Hifi_HIFI_WBS_Zero(lsu_main);
            //Hifi_HIFI_WBS_Zero(lsu_offset);
            Hifi_HIFI_WBS_Zero(mm1_6);
            Hifi_HIFI_WBS_Zero(mm2_generic);
            Hifi_HIFI_WBS_Zero(mm3);
            Hifi_HIFI_WBS_Zero(g1);
            Hifi_HIFI_WBS_Zero(g2);
            Hifi_HIFI_WBS_Zero(vd1);
            Hifi_HIFI_WBS_Zero(curl1);
            Hifi_HIFI_WBS_Zero(vd2);
            Hifi_HIFI_WBS_Zero(curl2);
            //Hifi_HIFI_WBS_Zero(freq_nx);
            //Hifi_HIFI_WBS_Zero(lsu_main);
            //Hifi_HIFI_WBS_Zero(lsu_offset);
            Hifi_HIFI_WBS_Zero(mm1_7);
            Hifi_HIFI_WBS_Zero(mm2_generic);
            Hifi_HIFI_WBS_Zero(mm3);
            Hifi_HIFI_WBS_Zero(g1);
            Hifi_HIFI_WBS_Zero(g2);
            Hifi_HIFI_WBS_Zero(vd1);
            Hifi_HIFI_WBS_Zero(curl1);
            Hifi_HIFI_WBS_Zero(vd2);
            Hifi_HIFI_WBS_Zero(curl2);
        }
    }
    //
}

// Chop between internal and external cold loads, block
// We take 1 spectrum per phase.
block Stability_intcold_extcold_fm HIFI 3424 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integration pairs 
    int integ_time = 4; //Total (co-added) integration time of ONE SINGLE phase in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "slowchop" in ["slowchop","fastchop"]; //Whether to use slowchop or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    Start_block();
    //Shutter_rotate_proc_fm("closed");
    //Get chopper settings
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_M3","chop_cold"],band,0.0);
    double chop_middle = result[0]{0};
    double chop_cold = result[1]{0};
    //
    //We implement a special slow-chop spectroscopy between
    //internal cold and external cold
    if(chopmode == "slowchop") {
        Slow_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_middle,chop_cold);
    } else {
        Fast_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_middle,chop_cold,chop_phase);
    }
}

{string,double,double}[] procedure HifiMappingModeFSwitchOTFNoRefSequencerInit {
    string modeName = "fs-raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period defines number of lines between two loads
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // inherit from load-chop mode
    {string,double,double}[] retvalues = HifiMappingProcLoadChopOTFNoRefSequencerInit(naifid,ra,dec,lineDistance,nlines,stepsize,npoints,band,lo_freq,effResolution,oneGHzReference,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_cycles,load_interval,docommands);

    return retvalues;
}

/////////////////////////////////////////
block FCU_config_mxdp_block_fm HIFI 3990 {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 522.0; //LO frequency  
}{
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get diplexer currents
    if(band_nb <= 2 || band_nb == 5) {
        double diplex_H = 0.0;
        //For bands 1, 2 and 5
        double diplex_V = 0.0;
    } else {
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    Hifi_HIFI_Config_mxbias_dpact($BBID,bias_H,bias_V,diplex_H,diplex_V);
    delay(1);
    //
    //In case of band 6 or 7, bias have been set to 4mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result_d[0]{0},result_d[1]{0});
    }
    //
}

//Band5
//LO parameter scan with HotCold measurement
//for Band 5a
procedure LCU5a_power_scan_with_Tsys {
    string band = "5a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4
    double lo_freq = 1150.0 in [1127.0,1178.0]; //LO frequency
    double param_min = 1.0; //Min. of scanned parameter
    double param_max = 2.0; //Max. of scanned parameter
    double step_size = 0.1; //Step size
    string param_name = "D2"; //Code of scanned parameter: M1,M2,M3,G1,G2,D1,D2.
    int integ_time = 4; //Total integration time in sec.
}{
    error("This module is obsolete: use LCU_power_scan_with_Tsys  instead");
}

//PDU switch off of a S/S, block
block PDU_switch_off_block_ops HIFI 7659 {
    string subsystem = "ICU_Prime" in ["ICU_Prime","ICU_Red","LO_Prime","LO_Red","WBS_H","WBS_V","HRS_H","HRS_V"];
}{
    if(subsystem != "ICU_Prime" && subsystem != "ICU_Red") {
        StartBlock_ops();
        //This has no delay
    }
    ////HifiIltEgse_PDU_switch_off($BBID,subsystem);	//The TEI command: WILL BE DONE BY SPACON
    mois_spacon("Please power OFF Sub-System " + subsystem);
    //delay(1);
}

//////////////////////////////////////////////////////////////////
// HRS complete configuration with maximum attenuation, block
// Both polarizations are treated
block HRS_config_max_att_block_fm HIFI 3634 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    //Start_block();
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrh_up_ol1_m = a_m_parameter[1];
    int hrh_up_ol1_a = a_m_parameter[0];
    int hrh_up_ol2_m = a_m_parameter[3];
    int hrh_up_ol2_a = a_m_parameter[2];
    int hrh_up_ol3_m = a_m_parameter[5];
    int hrh_up_ol3_a = a_m_parameter[4];
    int hrh_up_ol4_m = a_m_parameter[7];
    int hrh_up_ol4_a = a_m_parameter[6];
    int hrh_down_ol5_m = a_m_parameter[9];
    int hrh_down_ol5_a = a_m_parameter[8];
    int hrh_down_ol6_m = a_m_parameter[11];
    int hrh_down_ol6_a = a_m_parameter[10];
    int hrh_down_ol7_m = a_m_parameter[12];
    //V-polar
    int hrv_up_ol1_m = a_m_parameter[14];
    int hrv_up_ol1_a = a_m_parameter[13];
    int hrv_up_ol2_m = a_m_parameter[16];
    int hrv_up_ol2_a = a_m_parameter[15];
    int hrv_up_ol3_m = a_m_parameter[18];
    int hrv_up_ol3_a = a_m_parameter[17];
    int hrv_up_ol4_m = a_m_parameter[20];
    int hrv_up_ol4_a = a_m_parameter[19];
    int hrv_down_ol5_m = a_m_parameter[22];
    int hrv_down_ol5_a = a_m_parameter[21];
    int hrv_down_ol6_m = a_m_parameter[24];
    int hrv_down_ol6_a = a_m_parameter[23];
    int hrv_down_ol7_m = a_m_parameter[25];
    //Attenuators are fixed
    //H-polar
    double hrh_1u_att = 15.5;
    double hrh_1l_att = 15.5;
    double hrh_2u_att = 15.5;
    double hrh_2l_att = 15.5;
    double hrh_3u_att = 15.5;
    double hrh_3l_att = 15.5;
    double hrh_4u_att = 15.5;
    double hrh_4l_att = 15.5;
    //V-polar    
    double hrv_1u_att = 15.5;
    double hrv_1l_att = 15.5;
    double hrv_2u_att = 15.5;
    double hrv_2l_att = 15.5;
    double hrv_3u_att = 15.5;
    double hrv_3l_att = 15.5;
    double hrv_4u_att = 15.5;
    double hrv_4l_att = 15.5;
    //Configure HRS-H
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrh_1u_att,hrh_1l_att,hrh_2u_att,hrh_2l_att,hrh_3u_att,hrh_3l_att,hrh_4u_att,hrh_4l_att,hrh_up_ol1_m,hrh_up_ol1_a,hrh_up_ol2_m,hrh_up_ol2_a,hrh_up_ol3_m,hrh_up_ol3_a,hrh_up_ol4_m,hrh_up_ol4_a,hrh_down_ol5_m,hrh_down_ol5_a,hrh_down_ol6_m,hrh_down_ol6_a,hrh_down_ol7_m);
    //delay(hrs_config_delay);
    //
    //Configure HRS-V
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrv_1u_att,hrv_1l_att,hrv_2u_att,hrv_2l_att,hrv_3u_att,hrv_3l_att,hrv_4u_att,hrv_4l_att,hrv_up_ol1_m,hrv_up_ol1_a,hrv_up_ol2_m,hrv_up_ol2_a,hrv_up_ol3_m,hrv_up_ol3_a,hrv_up_ol4_m,hrv_up_ol4_a,hrv_down_ol5_m,hrv_down_ol5_a,hrv_down_ol6_m,hrv_down_ol6_a,hrv_down_ol7_m);
    delay(hrs_config_delay);
    //
    //Now Configure blocks
    HRS_config_resol_fm(band,hrs_mode);
}

{string,double,double}[] procedure HifiMappingModeFastDBSCrossSequencerInit {
    string modeName = "cross";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // inherit from dbs-raster mode
    {string,double,double}[] retvalues = HifiMappingProcFastDBSRasterSequencerInit(naifid,ra,dec,{0.0,double(npoints / 2) * stepsize},2,stepsize,npoints,band,lo_freq,effResolution,continuumDetection,oneGHzReference,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);

    return retvalues;
}

// OBS SFT, mode
mode HifiManCmd_OBS_SFT {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    Mode_status_check_intermediate();
    StartMode_block_ops();
    mois_comment("Start On-Board Software SFT");
    OBS_SFT_block_ops();
    StopMode_block_ops();
}

//Set LCU2b back to standby status, procedure
procedure LCU2b_standby_proc_fm {
    string band = "2b"; // HIFI band
    double lo_freq = 750.0 in [724.0,793.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

//Compute "real" frequencies
double procedure Compute_Real_Freq {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; //LO frequency
}{
    //Read parameters
    double[] result = CalibrationReader("name_lsu_convertion",["multiplier","f_offset","n10","n20"],band,lo_freq);
    double multiplier = result[0];
    double f_offset = result[1];
    int n10 = iround(result[2]);
    int n20 = iround(result[3]);
    //
    //Compute LSU frequency IN MHZ
    double f_lsu = lo_freq * 1000.0 / multiplier;
    //Compute total frequency
    double f_total = f_lsu + f_offset;
    //Compute parameter n
    int n = ifloor(15.0 * (f_total / 1.875 - double(ifloor(f_total / 1.875))));
    //Compute main and offset loop parameters
    int n1 = n10 + n;
    // offset loop
    int d1 = 15;
    //offset loop
    int n2 = iround(abs(double(n20 - ifloor(f_total / 1.875) + n)));
    //main loop
    int d2 = 16;
    //
    //Compute A,M and R parameters for main and offset loop
    int m1 = ifloor(double(n1) / 10.0) - 1;
    // offset loop	
    int a1 = n1 - 10 * ifloor(double(n1) / 10.0);
    // offset loop
    int r1 = d1 - 1;
    // offset loop
    int m2 = ifloor(double(n2) / 10.0) - 1;
    // main loop	
    int a2 = n2 - 10 * ifloor(double(n2) / 10.0);
    // main loop
    int r2 = d2 - 1;
    // main loop
    //
    int[] lsu_a_m_r_parameter = [0,0,0,0,0,0];
    lsu_a_m_r_parameter[0] = m1;
    lsu_a_m_r_parameter[1] = a1;
    lsu_a_m_r_parameter[2] = r1;
    lsu_a_m_r_parameter[3] = m2;
    lsu_a_m_r_parameter[4] = a2;
    lsu_a_m_r_parameter[5] = r2;
    //
    //Conversion into main and offset LSU word
    int main_word = iround(pow(2.0,18.0) * double(ifloor(double(r2) % pow(2.0,6.0) / pow(2.0,4.0))) + pow(2.0,15.0) * double(ifloor(double(m2) % pow(2.0,9.0) / pow(2.0,7.0))) + pow(2.0,8.0) * (double(m2) % pow(2.0,9.0)) + pow(2.0,4.0) * (double(r2) % pow(2.0,6.0) % pow(2.0,4.0)) + double(a2) % pow(2.0,4.0));
    int offset_word = iround(pow(2.0,18.0) * double(ifloor(double(r1) % pow(2.0,6.0) / pow(2.0,4.0))) + pow(2.0,15.0) * double(ifloor(double(m1) % pow(2.0,9.0) / pow(2.0,7.0))) + pow(2.0,8.0) * (double(m1) % pow(2.0,9.0)) + pow(2.0,4.0) * (double(r1) % pow(2.0,6.0) % pow(2.0,4.0)) + double(a1) % pow(2.0,4.0));
    //
    //debug_print("LSU conversion result " + lsu_a_m_r_parameter);
    //debug_print("main: " + main_word + ", offset: " + offset_word);
    //
    //Compute real LO frequency set by A,M,R combination
    double nn1 = double(10 * (m1 + 1) + a1);
    double dd1 = double(r1 + 1);
    double nn2 = double(10 * (m2 + 1) + a2);
    double dd2 = double(r2 + 1);
    double flsu_back = 24000.0 + 30.0 * (nn1 / dd1 + nn2 / dd2);
    if(band == "2a" || band == "3b") {
        flsu_back = 24000.0 + 30.0 * (nn1 / dd1 - nn2 / dd2);
    }
    double flo_back = flsu_back * multiplier;
    //debug_print("Real tuned frequency: " + flo_back);
    //

    return flo_back;
}

//////////////////////////////////////////////////////////
// Nominal configuration
/////////////////////////
//  LCU configuration AT START-UP into NOMINAL mode, procedure
procedure LCU_switchon_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //Clear potential failure mode
    Set_LO_Nominal_block_fm();
    //
    //We use a constant frequency for each band, regardless of the input
    double lo_freq = 0.0;
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq","midfreq","keyfreqwarm","keyfreq_dummy"],band,0.0);
    lo_freq = result_d[0];
    //this is for cold operations
    //   lo_freq = result_d[2];   //this is for warm operations
    //   lo_freq = result_d[3];     //this is for dummy operations
    ////FM_CUS_11.5: replace keyfreq by the only allowed frequency for warm IST
    //For band 7b, 1723.5 may be problematic. Take mid freq. instead
    //if (band == "7b") {
    //  lo_freq = result_d[1];  
    //  }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["switch_on_delay","config_lo_delay"],band,lo_freq);
    int switch_on_delay = iround(result[0]{0});
    int config_lo_delay = iround(result[1]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    drain2_v = cresult[0];
    //Send command: expect that we have already switched to NOMINAL
    //We set D2 to best guess and wait some time to stabilize chain temperature
    HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,switch_on_delay);
    //
    //Set heater to their switch-on value
    HL_heater_block_fm(band,"nominal");
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CUS scripts for HRS.
// HRS FT scripts are found under fm_FT_HRS.cus
//
// DT - 17-Feb-06
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The modes
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// See fm_testmodes.cus
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The blocks
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// HRS polar switch test - scenario proposed by NDW, block
procedure HRS_polar_switch_proc_fm {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    //
    //Get biases. No LO freq. given here.
    {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_low_resistive_h","bias_high_resistive_h","bias_low_resistive_v","bias_high_resistive_v"],band,0.0);
    double bias_low_h = result[0]{0};
    double bias_high_h = result[1]{0};
    double bias_low_v = result[2]{0};
    double bias_high_v = result[3]{0};
    //
    //some global settings 
    int integ_time = 4;
    string backend = "hrs";
    //Prepare magnets
    Set_Magnet_current_block_fm(0.0,0.0);
    //Set biases to 10mV - SPR-2110
    Mixerbias_block_fm(bias_high_h,bias_high_v);
    //
    //1. Configure HRS with normal switches: HRH on H, HRV on V
    HRS_config_w_switch_block_fm(band,hrs_mode,["H","V"]);
    //tune and take IF noise measurement
    HRS_tune_block_fm(band);
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //Take 5 and 10mV shot noise spectra
    Spectra_resistive_low_fm(band,bias_low_h,bias_low_v,integ_time,backend);
    Spectra_resistive_high_fm(band,bias_high_h,bias_high_v,integ_time,backend);
    //
    //2. Configure HRS with new switches: HRH on H, HRV on H
    HRS_config_w_switch_block_fm(band,hrs_mode,["H","H"]);
    //tune and take IF noise measurement
    HRS_tune_block_fm(band);
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //Take 5 and 10mV shot noise spectra
    Spectra_resistive_low_fm(band,bias_low_h,bias_low_v,integ_time,backend);
    Spectra_resistive_high_fm(band,bias_high_h,bias_high_v,integ_time,backend);
    //
    //3. Configure HRS with new switches: HRH on V, HRV on V
    HRS_config_w_switch_block_fm(band,hrs_mode,["V","V"]);
    //tune and take IF noise measurement
    HRS_tune_block_fm(band);
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //Take 5 and 10mV shot noise spectra
    Spectra_resistive_low_fm(band,bias_low_h,bias_low_v,integ_time,backend);
    Spectra_resistive_high_fm(band,bias_high_h,bias_high_v,integ_time,backend);
    //
    //4. back to standard setting
    //Need a representative frequency: take keyfreq
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result_d[0];
    result = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v","norm_bias_h","norm_bias_v"],band,lo_freq);
    double magnet_h = result[0]{0};
    double magnet_v = result[1]{0};
    double bias_h = result[2]{0};
    double bias_v = result[3]{0};
    HRS_config_w_switch_block_fm(band,hrs_mode,["H","V"]);
    Mixerbias_block_fm(bias_h,bias_v);
    Set_Magnet_current_block_fm(magnet_h,magnet_v);
}

// WBS reset, block
// Both polarizations are treated
block WBS_reset_block_fm HIFI 3602 {
}{
    //Fetch applicable HK rate
    {double,string}[] result_d = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    string hk_rate = result_d[0]{1};
    //Switch off HK request on WBS
    Hifi_HIFI_Housekeeping_on(hk_rate,"ON","ON","OFF","OFF","ON","ON");
    delay(1);
    Hifi_HIFI_reset_WBS_H($BBID);
    Hifi_HIFI_reset_WBS_V($BBID);
    delay(1);
    //Switch back on HK request on WBS
    Hifi_HIFI_Housekeeping_on(hk_rate,"ON","ON","ON","ON","ON","ON");
    delay(1);
    //
}

//HIFI-COP-1.2-FPU_FT
obs HifiEng_FPU_FT_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b","8"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(FPU_FT_COP_proc_ops(band,lo_freq,prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            FPU_FT_COP_proc_ops(band,lo_freq,prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

//HIFI investigation of diplexer with M1, procedure
//Perform diplexer scans at a series of M1 values
//Frequencies and M1 values to use are pre-tabulated
procedure Diplexerscan_M1_proc_fm_TV {
    string band = "7b" in ["3b","7b"]; // HIFI band
    int testblock = 1 in [1,3]; //Test block for 3b
}{
    mois_comment("Start of Diplexer scan investigation in band " + band);
    mois_comment("For this test, a special LCU safety table should have been uploaded via dedicated TPF files");
    //We will loop on tabulated frequencies
    //For each we will tune LO power and do diplexer scans
    //for various M1 settings for 7b, and M1/M2 combinations for 3b
    //1. Get the list of frequencies to be used for the scan
    string tab1 = "config_M1calib_" + band + "_TV.config";
    int total = table_size(tab1);
    if(band == "3b") {
        string tab2 = "config_M2calib_" + band + "_TV.config";
    }
    double[] freq = [];
    double[] m1_1 = [];
    double[] m1_2 = [];
    double[] m1_3 = [];
    double[] m1_4 = [];
    double[] m1_5 = [];
    double[] m1_6 = [];
    double[] m1_7 = [];
    double[] m1_8 = [];
    double[] m2_1 = [];
    double[] m2_2 = [];
    double[] m2_3 = [];
    double[] m3_1 = [];
    for(int j = 1 .. total) {
        freq[j] = dlookup(tab1,"" + j,"frequency");
        m1_1[j] = dlookup(tab1,"" + j,"m1_1");
        m1_2[j] = dlookup(tab1,"" + j,"m1_2");
        m1_3[j] = dlookup(tab1,"" + j,"m1_3");
        m1_4[j] = dlookup(tab1,"" + j,"m1_4");
        m1_5[j] = dlookup(tab1,"" + j,"m1_5");
        if(band == "3b") {
            m1_6[j] = dlookup(tab1,"" + j,"m1_6");
            m1_7[j] = dlookup(tab1,"" + j,"m1_7");
            m1_8[j] = dlookup(tab1,"" + j,"m1_8");
            m2_1[j] = dlookup(tab2,"" + j,"m2_1");
            m2_2[j] = dlookup(tab2,"" + j,"m2_2");
            m2_3[j] = dlookup(tab2,"" + j,"m2_3");
            m3_1[j] = dlookup(tab2,"" + j,"m3_1");
        }
        //Check whether this combination of band+freq is allowed in the current CUS
        Check_Band_vs_Freq_proc_fm(band,freq[j]);
    }
    //
    mois_step("Switch-on LO band");
    //Only if first testblock
    if(testblock == 1) {
        LCU_switchon_proc_fm(band);
        //Wait an extra delay of 10 min for mid term stabilization
        delay(600);
        //
    }
    mois_step("Loop on frequencies and multiplier settings");
    //Start loop on diplexer scans
    double[] m1_array = [];
    double[] m2_array = [];
    for(int i = 1 .. total) {
        //Configure FPU at that frequency
        Init_MSA_fm(band,"CLOSE",freq[i],"ON");
        //
        //Loop on M1 settings
        int nb_m1 = 5;
        int nb_m2 = 1;
        if(band == "3b") {
            m1_array = [m1_1[i],m1_2[i],m1_3[i],m1_4[i],m1_5[i],m1_6[i],m1_7[i],m1_8[i]];
            //now work with 3 blocks of 1 M2
            m2_array = [m2_1[i]];
            if(testblock == 2) {
                m2_array = [m2_2[i]];
            }
            if(testblock == 3) {
                m2_array = [m2_3[i]];
            }
            nb_m1 = 8;
            nb_m2 = 1;
            //3;  //now work with 3 blocks of 1 M2
        }
        if(band == "7b") {
            m1_array = [m1_1[i],m1_2[i],m1_3[i],m1_4[i],m1_5[i]];
            nb_m1 = 5;
        }
        //
        for(int k = 0 .. nb_m1 - 1) {
            //Band 7b: loop only on M1
            if(band == "7b") {
                //Prepare for diplexer scan
                //In case of band 6 or 7, use special biases
                if(band == "7b") {
                    {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v","bias_max_h","bias_max_v"],band,freq[1]);
                    //First go to 4mV
                    Mixerbias_block_fm(result[2]{0},result[3]{0});
                    //Then to 3mV
                    Mixerbias_block_fm(result[0]{0},result[1]{0});
                }
                //      
                //Use nominal diplexer values 
                double[] result_dip = Get_Diplexer_setting(band,freq[i]);
                Set_Diplexer_current_block_fm(result_dip[0],result_dip[1]);
                //First scan will be done at max Vd2
                LCU_config_w_M1_block_fm(band,freq[i],m1_array[k]);
                //Perform diplexer scan at that frequency and M1 setting
                double diplexer_current_min_h = -2.24;
                double diplexer_current_max_h = 2.24;
                double diplexer_current_step = -0.073;
                //i.e. approx 4.48/61
                int n_steps = 61;
                double stepTime = 0.1;
                //
                Scan_diplexer_block_fm(band,diplexer_current_max_h,diplexer_current_max_h,diplexer_current_step,n_steps,stepTime);
                //Add delay in order to get 30 sec between first tuning macro and this scan
                //delay(16);  //no delay now since req is 30sec between 2 subsequent TM
                Scan_diplexer_block_fm(band,diplexer_current_max_h,diplexer_current_max_h,diplexer_current_step,n_steps,stepTime);
                //Back to nominal diplexer values for next tuning
                result_dip = Get_Diplexer_setting(band,freq[i]);
                Set_Diplexer_current_block_fm(result_dip[0],result_dip[1]);
                //In case of band 6 or 7,go back to nominal bias values for next LO tuning
                if(band == "7b") {
                    result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,freq[1]);
                    //First go to 4mV
                    Mixerbias_block_fm(result[0]{0},result[1]{0});
                    //Then to nominal
                    result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,freq[1]);
                    Mixerbias_block_fm(result[0]{0},result[1]{0});
                }
                //Second diplexer scan at Vd2max - 100mV, or best-guess
                //Perform LO tuning at that frequency and M1 to get a reasonable pumping level
                LO_tuning_w_M1_block_fm(band,freq[i],m1_array[k]);
                //message(band+", "+freq[i]+", "+m1_array[k]);           
                //Now prepare for diplexer scan
                //In case of band 6 or 7, use special biases
                if(band == "7b") {
                    result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v","bias_max_h","bias_max_v"],band,freq[1]);
                    //First go to 4mV
                    Mixerbias_block_fm(result[2]{0},result[3]{0});
                    //Then to 3mV
                    Mixerbias_block_fm(result[0]{0},result[1]{0});
                }
                //
                Scan_diplexer_block_fm(band,diplexer_current_max_h,diplexer_current_max_h,diplexer_current_step,n_steps,stepTime);
                //
            }
            if(band == "3b") {
                for(int l = 0 .. nb_m2 - 1) {
                    //Prepare for diplexer scan
                    //Use nominal diplexer values 
                    result_dip = Get_Diplexer_setting(band,freq[i]);
                    Set_Diplexer_current_block_fm(result_dip[0],result_dip[1]);
                    //Set the maximum Vd2 available 
                    LCU_config_w_M1M2M3_block_fm(band,freq[i],m1_array[k],m2_array[l],m3_1[i]);
                    //message(band+", "+freq[i]+", "+m1_array[k]+", "+m2_array[l]+", "+m3_1[i]);  
                    //Perform diplexer scan at that frequency and M1 setting
                    diplexer_current_min_h = -2.24;
                    diplexer_current_max_h = 2.24;
                    diplexer_current_step = -0.073;
                    //i.e. approx 4.48/61
                    n_steps = 61;
                    stepTime = 0.1;
                    //
                    //Perform 2 diplexer scans: one immediately after, and one X sec after the tuning macro
                    //so that total time between tuning macros is 1min, or 30sec between tuning macro and 2nd scan
                    Scan_diplexer_block_fm(band,diplexer_current_max_h,diplexer_current_max_h,diplexer_current_step,n_steps,stepTime);
                    //
                    //Add delay:
                    //For one minute between each tuning macro: 25sec more on average
                    //For 30sec between tuning macro and second scan: 16sec more on average
                    //Req. is now: 30sec between 2 tuning macros -> 4sec
                    delay(4);
                    //Second scan
                    Scan_diplexer_block_fm(band,diplexer_current_max_h,diplexer_current_max_h,diplexer_current_step,n_steps,stepTime);
                }
            }
            //
        }
    }
    //In case of band 6 or 7,go back to nominal values at end of loop
    if(band == "7b") {
        result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,freq[1]);
        //First go to 4mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
        //Then to nominal
        result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,freq[1]);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //
    mois_comment("At the end of this test, the standard LCU safety table should be uploaded again.");
}

// Standing wave analysis
// This is the testmode to loop on all parameters for total time estimate
//HIFI-COP-3-StWv1
obs HifiManCmd_standing_wave_noretune_MOIS {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //General parameters in use
    string backend = "both";
    string[] hrs_mode = ["mr","mr"];
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Standing_wave_noretune_MOIS_proc_ops(band,backend,hrs_mode));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Standing_wave_noretune_MOIS_proc_ops(band,backend,hrs_mode);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// Initialisation of FPU, block with both MSA in use
// Looks at the hot load !
// It is for cold context !
block Init_MSA_SKY_fm HIFI 3997 {
    string band = "1a"; // HIFI band
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
    string hbb_heater = "ON" in ["ON","OFF"]; //hot source on/off
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    if(hbb_heater == "ON") {
        result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,lo_freq);
        calibcurrent = result_d[0]{0};
    }
    //
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_confilfpu",["chop_M3"],band,0.0);
    //result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],
    // 						     band,0.0);  
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //In case of band 6 or 7, bias have been set to 4mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    //Magnet are so far at maximum value. Now set to nominal
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
        Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
        delay(1);
    }
    //
    //Hifi_HIFI_non_periodic_hk_FCU ();
}

/////////////////////////////////////////
// Testmodes for handling of LCU safety
// tables and memory patches
// AdJ - 17-08-2006: initial version
// DT  - 16-04-2007: reviewed for MOC
/////////////////////////////////////////
//Upload of partial LCU safety tables partial mode
//Prime/Redundant is handled with the CUS table
//Required for flight procedures as total number of command parameters
//is limited to 999
mode HifiManCmd_upload_LCU_table_flight_ops {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string section = "P" in ["P","R"];
    int start = 0;
    int count = 450 in [0,450];
}{
    mois_comment("This procedure MUST be performed after the LCU memory patch HIF_CUPM");
    string tab = "LcuSafetyTable_" + section + ".config";
    int lastline = imin(table_size(tab),start + count);
    int firstline = start + 1;
    mois_comment("Start LCU table upload from line " + firstline + " until line " + lastline);
    mois_tmcheck("Verify that parameter HL_Mode_S is set to standby.");
    StartMode_block_ops();
    mois_step("Perform safety table upload");
    LcuSafetyTableUpload_ops(section,start,count);
    StopMode_block_ops();
}

// Measurement done after HRS 0-lag freqscan, procedure
// We measure a short stability TP and a long Y-factor in fast-chop
procedure Proc_Hotcold_w_stability {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 522.0; //Operative LO freq to be tuned in GHz
    int n = 100; //Number of TP measurement during stability
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total (co-added) integration time of a phase in sec.
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length for Y-factor in fastchop
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_cold_ang");
    //Look at CBB
    //
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
    }
    //Tune at user input LO frequencies.
    LO_tuning_block_fm(band,lo_freq);
    //
    //Magnet tuning: only up to band 5 since band6-7 have no magnets
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        {double,string}[] result_d = ConfigurationReader("name_configwbs",["tune_target_magnet"],band,lo_freq);
        int tune_target_magnet = iround(result_d[0]{0});
        Magnet_tuning_block_fm(band,lo_freq,"HRS",tune_target_magnet);
        //HRS is preferred
    }
    //
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both") {
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        HRS_tune_block_fm(band);
    }
    //
    //
    //Total power stability measurement: WBS only, 2sec. for B1-5, 1sec for B6-7 TP
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        Stability_intcold_fm(band,n,2,"wbs",hrs_mode,"tp",chop_phase);
    } else {
        Stability_intcold_fm(band,n,1,"wbs",hrs_mode,"tp",chop_phase);
    }
    //Take Y-factor during ~10 sec. on each load in fastchop
    //Configure spectrometers integration: this only applies to the Y-factor fastchop
    //Integ_time expected here is the TOTAL integration time with both phases + residual HRS time
    int[] res = Configure_Spectrometer_fast_chop_proc_fm(band,integ_time * 2,chop_phase,hrs_mode,backend);
    integ_time = iceil(chop_phase * double(res[1] * res[2]));
    //debug_print("Fast chop parameters: n_wbs1 = "+res[2]+", n_hrs_trans = "+res[3]);
    int n_wbs1 = res[2];
    int n_hrs_trans = res[3];
    //Y-factor measurement
    Hot_cold(band,hrs_mode,backend,integ_time,"fastchop",n_wbs1,n_hrs_trans);
    //
}

// FPU Standby with HBB ON, block
block Band0_hbb_on_block_ops HIFI 7298 {
    string band = "0"; // HIFI band
    string chop_loop = "CLOSE"; // Chopper Loop status
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current_on"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //  
    double calibcurrent = result_d[7]{0};
    //
    result_d = ConfigurationReader("name_confilfpu",["bias_standby_h","diplexer_standby_h","bias_standby_v","diplexer_standby_v","diplex_h_ctrl_mode","diplex_v_ctrl_mode","chop_M3right"],band,0.0);
    //
    double bias_H = result_d[0]{0};
    double diplex_H = result_d[1]{0};
    double bias_V = result_d[2]{0};
    double diplex_V = result_d[3]{0};
    int diplex_h_ctrl_mode = iround(result_d[4]{0});
    int diplex_v_ctrl_mode = iround(result_d[5]{0});
    double chopper = result_d[6]{0};
    //
    //Retrieve magnets.
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_standby_h","magnet_standby_v"],band,0.0);
        double magnetcurrent_H = result_d[0]{0};
        double magnetcurrent_V = result_d[1]{0};
    }
    //
    //Upconverter: should be kept ON at this stage. No particular action.
    //
    if(prime_or_redundant == "Prime") {
        Hifi_HIFI_P_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    } else {
        Hifi_HIFI_R_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    }
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    Hifi_HIFI_non_periodic_hk_FCU();
    //
    mois_tmcheck("Check that parameter HF_APR_CS_C is set to " + calibcurrent + " mA");
    mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to " + chop_loop);
    mois_tmcheck("Check that parameter HF_DPR_CHSINE_S is set to " + chop_sine_s);
}

//Check consistency between frequency and M1 choice for 7b
bool procedure Check_M1_vs_Freq_proc_fm {
    string band = "7b" in ["7b","7b"]; // HIFI band   
    double lo_freq = 1800.0; //LO frequency
    double m1 = -6.0; //M1 multiplier voltage
}{
    bool go_ahead_m1 = true;
    string name_configlcu = "name_configlcu_b";
    {double,string}[] result = ConfigurationReader(name_configlcu,["m1_v"],band,lo_freq);
    double m1_v = result[0]{0};
    if(m1 > m1_v || m1 < -8.5) {
        go_ahead_m1 = false;
    }
    if(go_ahead_m1 == false) {
        error("M1 not within allowed range (-8.5 to " + m1_v + " V) for band " + band);
    }

    return go_ahead_m1;
}

//Notify PDU status ON, block
//I assume all S/S are present
block HIFI_notify_PDU_status_on_block_ops HIFI 7655 {
    string status_FCU = "ON" in ["ON","OFF"]; //Status of FCU
    string status_LCU = "ON" in ["ON","OFF"]; //Status of LCU
    string status_WBSV = "ON" in ["ON","OFF"]; //Status of WBSV
    string status_WBSH = "ON" in ["ON","OFF"]; //Status of WBSH
    string status_HRSV = "ON" in ["ON","OFF"]; //Status of HRSV
    string status_HRSH = "ON" in ["ON","OFF"]; //Status of HRSH
    string apply_to_subsystem = "FCU" in ["FCU","LCU","WBSH","WBSV","HRSH","HRSV","ALL"];
}{
    StartBlock_ops();
    //This has no delay 
    Hifi_HIFI_notify_PDU_status(status_FCU,status_LCU,status_WBSV,status_WBSH,status_HRSV,status_HRSH);
    delay(1);
    //Prepare message for operator: we will check whether one particular HK is ON
    if(status_FCU == "ON") {
        string subsyst_on = "HI_FCU_S";
    }
    if(status_WBSH == "ON") {
        subsyst_on = "HI_WBSH_S";
    }
    if(status_WBSV == "ON") {
        subsyst_on = "HI_WBSV_S";
    }
    if(status_HRSH == "ON") {
        subsyst_on = "HI_HRSH_S";
    }
    if(status_HRSV == "ON") {
        subsyst_on = "HI_HRSV_S";
    }
    if(status_LCU == "ON") {
        subsyst_on = "HI_LCU_S";
    }
    mois_tmcheck("Check that the HK parameter " + subsyst_on + " is ON.");
    //Specific S/S check after switch on
    if(apply_to_subsystem == "FCU" || apply_to_subsystem == "ALL") {
        //Nothing in particular
    }
    if(apply_to_subsystem == "WBSH" || apply_to_subsystem == "ALL") {
        //This is now done at end of procedure as instrument mode status check
        //mois_tmcheck("Check that both parameters HWH_Laser1_S and HWH_Laser2_S are OFF");
        //mois_tmcheck("Check that parameter HWH_Zero_S is ON");
        //mois_tmcheck("Check that parameter HWH_IN_ATT is set to 15, and parameters HWH_Band_1_ATT, HWH_Band_2_ATT, HWH_Band_3_ATT, HWH_Band_4_ATT are set to 7");
    }
    if(apply_to_subsystem == "WBSV" || apply_to_subsystem == "ALL") {
        //This is now done at end of procedure as instrument mode status check
        //mois_tmcheck("Check that both parameters HWV_Laser1_S and HWV_Laser2_S are OFF");
        //mois_tmcheck("Check that parameter HWV_Zero_S is ON");
        //mois_tmcheck("Check that parameter HWV_IN_ATT is set to 15, and parameters HWV_Band_1_ATT, HWV_Band_2_ATT, HWV_Band_3_ATT, HWV_Band_4_ATT are set to 7");
    }
    if(apply_to_subsystem == "HRSH" || apply_to_subsystem == "ALL") {
        //This is now done at end of procedure as instrument mode status check
        //mois_tmcheck("Check that parameters HRH_1U_ATT, HRH_1L_ATT, HRH_2U_ATT, HRH_2L_ATT, HRH_3U_ATT, HRH_3L_ATT, HRH_4U_ATT and HRH_4L_ATT are set to 15.5"); 
    }
    if(apply_to_subsystem == "HRSV" || apply_to_subsystem == "ALL") {
        //This is now done at end of procedure as instrument mode status check
        //mois_tmcheck("Check that parameters HRV_1U_ATT, HRV_1L_ATT, HRV_2U_ATT, HRV_2L_ATT, HRV_3U_ATT, HRV_3L_ATT, HRV_4U_ATT and HRV_4L_ATT are set to 15.5");   
    }
    if(apply_to_subsystem == "LCU" || apply_to_subsystem == "ALL") {
        //This is now done at end of procedure as instrument mode status check
        //mois_tmcheck("Check that parameter HL_MODE_S is standby");
        //mois_tmcheck("Check that parameter HL_Channel_S is OFF");
    }
}

//General script to read TM1, TM2,etc, block
block LCU_Read_TM_pages_OLD_block_fm HIFI 3968 {
}{
    //Re-implement old way to be consistent with MOIS manual procedures
    //
    //Get various TM pages. This will clear error flags too
    //Hifi_HIFI_LCU_all_tuning_hk();
    //delay(2);
    /////////////////////////////////////
    //Temporary work-around for TVTB SFT
    //Get various TM pages
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM1");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM2");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM3");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_G");
    delay(2);
    //
    //Clear error flags
    Hifi_HIFI_LCU_Single($BBID,"HL_CLR_ERR");
    //
}

// Total noise from an OTF observation
// 
double procedure OtfNoise {
    double n = 10.0; // number of points in one scan
    double[] parameters = [0.02,0.4,0.05,0.667,2.5]; // Parameters: integration time, delay, slew from OFF relative to Allan time, ratio of t_off time to sqrt(n)*t_on, drift exponent
}{
    {double,double} noisevalues = OtfNoiseValues(n,parameters);
    double y = noisevalues{0} + noisevalues{1};

    return y;
}

//Set LCU2a back to standby status, procedure
procedure LCU2a_standby_proc_fm {
    string band = "2a"; // HIFI band
    double lo_freq = 700.0 in [647.0,710.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

///////////////////////////////////////////////////
// CUS scripts thermal monitoring of the FPU. 
// Based on SCOE tests initially performed for
// the QM by BK.
// They are here updated for FM. There will be
// independent tests for respective H and V.
//
// DT - 17/11/04: first draft for FM. Thermal test
//		  new has been removed.
//
///////////////////////////////////////////////////
//modes: see fm_testmodes.cus
/////////////////////////////////////////////
// Blocks for thermal tests
/////////////////////////////////////////////
// thermal tests
block Thermal_fm HIFI 3280 {
    string band = "1a"; // HIFI band
    double lo_freq = 522.0; //LO frequency
}{
    //Start_block();
    //Get band number
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    //
    //Get Targetted values for magnet, mixer bias, heater time and diplexer
    double[] cresult_d = CalibrationReader("name_configthermal",["dipl_h","magn_h","mbias_h","heat_h","dipl_v","magn_v","mbias_v","heat_v"],band,0.0);
    double target_dipl_h = cresult_d[0];
    double target_magn_h = cresult_d[1];
    double target_mbias_h = cresult_d[2];
    double target_heat_h = cresult_d[3];
    double target_dipl_v = cresult_d[4];
    double target_magn_v = cresult_d[5];
    double target_mbias_v = cresult_d[6];
    double target_heat_v = cresult_d[7];
    //
    int diplex_h_ctrl_mode = 0;
    //
    //IF amplifiers should be set to standby values
    result_d = ConfigurationReader("name_confilfpu",["fif1v_h","fif1c_h","fif2v_h","fif2c_h"],"0",0.0);
    double volt_H_FIF_1 = result_d[0]{0};
    double curr_H_FIF_1 = result_d[1]{0};
    double volt_H_FIF_2 = result_d[2]{0};
    double curr_H_FIF_2 = result_d[3]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],"0",0.0);
    double volt_H_SIF_1 = result_d[0]{0};
    double curr_H_SIF_1 = result_d[1]{0};
    double volt_H_SIF_2 = result_d[2]{0};
    double curr_H_SIF_2 = result_d[3]{0};
    double volt_H_SIF_3 = result_d[4]{0};
    double curr_H_SIF_3 = result_d[5]{0};
    //
    int diplex_v_ctrl_mode = 0;
    //
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v"],"0",0.0);
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    result_d = ConfigurationReader("name_confilfpu",["sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],"0",0.0);
    double volt_V_SIF_1 = result_d[0]{0};
    double curr_V_SIF_1 = result_d[1]{0};
    double volt_V_SIF_2 = result_d[2]{0};
    double curr_V_SIF_2 = result_d[3]{0};
    double volt_V_SIF_3 = result_d[4]{0};
    double curr_V_SIF_3 = result_d[5]{0};
    //
    string chop_sine_s = "ON";
    string chop_loop = "CLOSE";
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3"],band,lo_freq);
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,lo_freq);
    double calibcurrent = result_d[0]{0};
    //Initialize settings
    double bias_H = 0.0;
    double magnetcurrent_H = 0.0;
    double diplex_H = 0.0;
    double bias_V = 0.0;
    double magnetcurrent_V = 0.0;
    double diplex_V = 0.0;
    //Look at CBB at start of test
    result_d = ConfigurationReader("name_confilfpu",["chop_cold"],band,lo_freq);
    double chopper = result_d[0]{0};
    chopper = Check_Chopper_Prime_Redundant(chopper);
    //
    //Start modification of FPU parameters - This is also the 0 of the test clock
    //1. Initial configuration with the chopper moving to M3 middle 
    //   and diplexer_H set to targetted value
    //
    //Diplexer is only used for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        diplex_H = target_dipl_h * 1.0;
        diplex_V = target_dipl_v * 0.0;
        //
        HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
        //
        delay(900);
        //
        //Actuate diplexer_V
        diplex_H = target_dipl_h * 1.0;
        diplex_V = target_dipl_v * 1.0;
        //
        HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
        //
        delay(900);
    }
    //
    //2. Set IF1 ON
    //
    result_d = ConfigurationReader("name_confilfpu",["fif1v_h","fif1c_h","fif2v_h","fif2c_h"],band,lo_freq);
    volt_H_FIF_1 = result_d[0]{0};
    curr_H_FIF_1 = result_d[1]{0};
    volt_H_FIF_2 = result_d[2]{0};
    curr_H_FIF_2 = result_d[3]{0};
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(900);
    //
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v"],band,lo_freq);
    volt_V_FIF_1 = result_d[0]{0};
    curr_V_FIF_1 = result_d[1]{0};
    volt_V_FIF_2 = result_d[2]{0};
    curr_V_FIF_2 = result_d[3]{0};
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(900);
    //
    //3. Set IF2 ON
    //
    result_d = ConfigurationReader("name_confilfpu",["sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    volt_H_SIF_1 = result_d[0]{0};
    curr_H_SIF_1 = result_d[1]{0};
    volt_H_SIF_2 = result_d[2]{0};
    curr_H_SIF_2 = result_d[3]{0};
    volt_H_SIF_3 = result_d[4]{0};
    curr_H_SIF_3 = result_d[5]{0};
    // 
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(900);
    //
    result_d = ConfigurationReader("name_confilfpu",["sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    volt_V_SIF_1 = result_d[0]{0};
    curr_V_SIF_1 = result_d[1]{0};
    volt_V_SIF_2 = result_d[2]{0};
    curr_V_SIF_2 = result_d[3]{0};
    volt_V_SIF_3 = result_d[4]{0};
    curr_V_SIF_3 = result_d[5]{0};
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(900);
    //
    //5. Magnet current to max., then to dedicated value for thermal test
    if(band_nb <= 5) {
        //Set to targetted values
        magnetcurrent_H = target_magn_h;
        //
        //Magnet-H
        HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
        delay(900);
        magnetcurrent_V = target_magn_v;
        //
        //Magnet-V
        HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
        delay(900);
    }
    //
    //6. Bias voltage to dedicated value for thermal test
    bias_H = target_mbias_h;
    //H-bias
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(900);
    //V-bias
    bias_V = target_mbias_v;
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(900);
    //
    //7.Turn everything off
    bias_H = 0.0;
    bias_V = 0.0;
    magnetcurrent_H = 0.0;
    magnetcurrent_V = 0.0;
    diplex_H = 0.0;
    diplex_V = 0.0;
    //
    result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],"0",0.0);
    //
    volt_H_FIF_1 = result_d[1]{0};
    curr_H_FIF_1 = result_d[2]{0};
    volt_H_FIF_2 = result_d[3]{0};
    curr_H_FIF_2 = result_d[4]{0};
    volt_H_SIF_1 = result_d[5]{0};
    curr_H_SIF_1 = result_d[6]{0};
    volt_H_SIF_2 = result_d[7]{0};
    curr_H_SIF_2 = result_d[8]{0};
    volt_H_SIF_3 = result_d[9]{0};
    curr_H_SIF_3 = result_d[10]{0};
    //
    {double,string}[] result_d2 = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],"0",0.0);
    //
    volt_V_FIF_1 = result_d2[0]{0};
    curr_V_FIF_1 = result_d2[1]{0};
    volt_V_FIF_2 = result_d2[2]{0};
    curr_V_FIF_2 = result_d2[3]{0};
    //
    volt_V_SIF_1 = result_d2[4]{0};
    curr_V_SIF_1 = result_d2[5]{0};
    volt_V_SIF_2 = result_d2[6]{0};
    curr_V_SIF_2 = result_d2[7]{0};
    volt_V_SIF_3 = result_d2[8]{0};
    curr_V_SIF_3 = result_d2[9]{0};
    //
    HIFI_Configure_FCU_proc_fm(0,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(1200);
    //
    //12. Check heater current effect on temperature: Let current ON
    //    during the standard deflux time.
    //First, call same FPU configuration, but specify band to be used to switch on band again
    //We will bias the junction to check when 
    //the heater effect is effective
    result_d = ConfigurationReader("name_confilfpu",["bias_very_low_h","bias_very_low_v"],band,lo_freq);
    bias_H = result_d[0]{0};
    bias_V = result_d[1]{0};
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(3);
    //
    //Get time during which one wants to send the pulse
    double max_heater_time_h = target_heat_h * 1000.0;
    //in msec
    double max_heater_time_v = target_heat_v * 1000.0;
    //in msec
    //Start to send the pulse
    //H-heater
    Hifi_HIFI_HF_CH1_DHTR_C($BBID,max_heater_time_h);
    //delay(iceil(max_heater_time_h / 1000.0) + 1);
    delay(600);
    //V-heater
    Hifi_HIFI_HF_CV1_DHTR_C($BBID,max_heater_time_v);
    //delay(iceil(max_heater_time_v / 1000.0) + 1);
    delay(1200);
    //
    //13. Chop to HBB
    result_d = ConfigurationReader("name_confilfpu",["chop_hot"],band,lo_freq);
    chopper = result_d[0]{0};
    chopper = Check_Chopper_Prime_Redundant(chopper);
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(600);
    //14. Chop back to CBB
    result_d = ConfigurationReader("name_confilfpu",["chop_cold"],band,lo_freq);
    chopper = result_d[0]{0};
    chopper = Check_Chopper_Prime_Redundant(chopper);
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(600);
    //
}

// Global frequency switch spectroscopy for stability measurement, procedure
// We assume it works like fast chop
procedure Freqswitch_spectro_for_Stability_proc_fm {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integration pairs 
    int integ_time = 8; //Total (co-added) integration time of a phase in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Compute data_time and n_switch using the wrapper
    int[] res = ConfigSlowChop(integ_time,"fs",band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_switch = n * res[1];
    //For stability measurement, the number of loop is a user input
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS.
    // The deadtimes output is not used at ILT level.
    {double,double} dtimes = ConfigSpectroscopySlowChop(data_time,n_switch,"fs",band,0.0,backendreadoutparms,true);
    //Compute data-rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //Now start the long integration
    Hifi_HIFI_Spectr_freq_switch($BBID);
    //
    Apply_Slow_Chop_delay(data_time * n_switch,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

//////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the observing mode
{double,double,double,double,double} procedure SScanFSwitch_noisecomputer {
    string band = "4a"; // HIFI band
    double reffreq = 978300.0; // Reference LO frequency in scan center
    int nfreq = 4; // Number of frequency points per IF
    bool dsb = true; // Both sidebands covered
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    int on_inttime = 16; // Integration time per ON phase
    int off_inttime = 16; // Integration time per OFF phase
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double,double,double} tact = {10.0,4.9,4.9,0.05,0.05}; // Field of actual dead and integration times
}{
    // spectral scans always use the full bandwidth for reference
    bool oneGHzReference = false;
    // Call FS noise computer
    {double,double,double,double,double} noisevalues = FSwitch_noisecomputer(band,reffreq,eff_resolution,oneGHzReference,on_inttime,off_inttime,n_cycles,tscan,tact);
    // Correct for multiple frequencies
    double multiplier = sqrt(1.0 / double(nfreq));
    noisevalues{0} = noisevalues{0} * multiplier;
    noisevalues{1} = noisevalues{1} * multiplier;
    // Check for double sideband coverage
    if(dsb) {
        // Combine LSB-USB noise
        // In spectral scans we have only a combined noise temperature for both
        // sidebands, so that the USB/LSB separation is not used
        double[] gssb = InterpolateGssb(band,reffreq);
        double usbnoise_lores = noisevalues{0} / sqrt(1.0 + gssb[1] / gssb[0] * (gssb[1] / gssb[0]));
        double usbnoise_hires = noisevalues{1} / sqrt(1.0 + gssb[1] / gssb[0] * (gssb[1] / gssb[0]));
        double lsbnoise_lores = usbnoise_lores;
        double lsbnoise_hires = usbnoise_hires;
    } else {
        // Get single sideband noise equivalent
        usbnoise_lores = noisevalues{0};
        usbnoise_hires = noisevalues{1};
        lsbnoise_lores = noisevalues{2};
        lsbnoise_hires = noisevalues{3};
    }
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noisevalues{4}};
}

// Length of a vector in degrees
double procedure VectorLength {
    {double,double} vector = {1.0,1.0};
}{

    return sqrt(vector{0} * vector{0} + vector{1} * vector{1});
}

// FPU settling time for a mixer band change, 2nd block
// Block for second tuning
block FPU_Settling_time_second_tuning_fm HIFI 3684 {
    string band_2 = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int int_time2 = 600; //Integration time after first and second switch
    double lo_freq_2 = 500.0; //LO frequency in sub-band b
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //
    //
    //Init and tune of LO: configuration from safe to tuned.
    LCU_config_nominal_proc_fm(band_2,lo_freq_2);
    LO_tuning_w_mixerchoice_proc(band_2,lo_freq_2,"H");
    //
    //Configure spectroscopy integration
    Configure_Spectrometer_proc_fm(band_2,int_time2,["wb1","wb1"],backend);
    //4 sec. integration
    //Take series of spectra during int_time2 seconds
    HIFI_Spectr_total_power_proc_fm(band_2,backend,int_time2);
    //
    //Now switch off LO sub-band
    LCU_switch_off_proc_fm();
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the DBS raster mode
procedure FastDBSRaster_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 10 in [4,80]; // data dump interval
    int n_int = 20; // number chop cycles to integrate in ICU before transfer
    int n_seq = 1; // number of data transfer cycles per pointing
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF cycles 
    int n_pointsperscan = 1; // Number of points measured before moving to the second pointing phase
    int n_loadinterval = 10; // number of nods before a load measurement
    int n_load = 0; // additional load measurements in one pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,10,0,10,20,21,0,0,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    bool iscross = false; // Whether we use a cross instead of a raster
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Fixed timings in the fast-chop mode
    int load_datatime = GetStdLoadReadout(band,lo_freq);
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time / 2);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,true);
    int readoutdead = FastChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // There is no nod counter in the return values - count this by hand
    int inod = 0;
    // Do I have to make loads in short nods and subsequent holds?
    if(iscross) {
        bool holdforload = n_pointsperscan > 1;
    } else {
        holdforload = n_pointsperscan == 1 && n_loadinterval > n_cycles;
    }
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    int[] choppars = [2 * n_int,0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - hkduration - loadlength);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            runintostate = false;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            // The use of n_load differs by 1 from the other observing modes here
            for(int i1 = 1 .. n_load - 1) {
                HIFIFastChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFIFastChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            // n_pointsperscan=1, n_loadinterval > n_cycles
            if(state[3] % 2 == 1) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
        }
        // Second pointing phase
        if(state[0] == 7) {
            // second nod position
            choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            for(int i2 = 1 .. n_load - 1) {
                HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle 
            HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            if(state[3] % 2 == 0) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
        }
        // Load nod
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            runintostate = false;
        }
        // Hold
        if(state[0] == 6) {
            // finished shift of instrument operations relative to pointing command
            runintostate = false;
        }
        // Final load
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

{string,double,double}[] procedure HifiSScanModeLoadChopNoRefSequencerInit {
    string modeName = "load-freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_cycles = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    // inherit from fs-noref mode
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {string,double,double}[] retvalues = HifiPointProcLoadChopNoRefSequencerInit(naifid,ra,dec,band,reffreq,effResolution,narrowReference,hr1,hr2,wb1,wb2,data_time,n_cycles,load_interval,docommands);
    retvalues[1] = {"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)};

    return retvalues;
}

//TM check when rescue mode: very difficult to identify as such.
//Is based on the reception/non-reception of certain event packets
procedure Mode_status_check_rescue {
    string context = "normal" in ["normal","failure"]; //indicate if this is a normal or failure arrival to rescue
}{
    mois_comment("Checking instrument status in rescue mode");
    if(context == "failure") {
        mois_tmcheck("Check that the previous execution of either of the telecommands: Hifi_HIFI_force_bootdefault or Hifi_HIFI_force_bootpartition, has resulted in either of the following: no (5,1) packet was received, or a (5,4) packet was received.");
    }
    if(context == "normal") {
        mois_tmcheck("The ICU should be powered ON");
    }
}

////////////////////////////////////////////////////////////////////////
// Radiometric noise from an OTF observation
// This is still to be scaled by a factor 1.0/(B_fluct*T_A)
double procedure OtfRadioNoise {
    double x = 0.02; // integration time (everything relative to the Allan time)
    double xr = 0.06; // reference integration time
    double d1 = 0.3; // time difference between last OFF and point
    double d2 = 0.3; // time difference between point and next OFF
}{
    if(x > 0.0 && xr > 0.0) {
        // Auxiliary parameters
        double l = (d2 + 0.5 * (xr + x)) / (d1 + d2 + xr + x);
        double ladd = 1.0 - 2.0 * l + 2.0 * l * l;
        //
        // finally the radiometric noise
        double y = 1.0 / x + ladd / xr;
    } else {
        // forbid x values <=0
        y = 1.0E11 * (1.0 - x);
    }

    return y;
}

// Spectrometer configuration for fast chop, low level procedure
int[] procedure Configure_Spectrometer_fast_chop_proc_fm {
    string band = "1a"; // HIFI band
    int integ_time = 8; //Total integation time of the two phases in seconds
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length for fast chop
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Compute data_time and n_switch using the wrapper
    int[] res = ConfigFastChop(integ_time,chop_phase,band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_data = res[1];
    int n_chop = res[2];
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS.
    // The deadtimes output is not used at ILT level.
    {{double,double,double},{int,int}} pars = ConfigSpectroscopyFastChop_IST(chop_phase,n_chop,n_data,band,0.0,backendreadoutparms);
    //
    int[] final_res = [res[0],res[1],pars{1}{0},pars{1}{1}];

    return final_res;
}

// BLOCK : Functional Test No 2 (HRS Square S Internal Test)
block HRS_functional_test_No_2_Square_s_block_fm HIFI 3621 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //Fill in block parameter names for each mode - consequence of SPR-0198
    string[] hrs_blocks_square_s_ultra = ["square_s_ultra","square_s_ultra","square_s_ultra","square_s_ultra","square_s_ultra","square_s_ultra","square_s_ultra","square_s_ultra"];
    string[] hrs_blocks_square_s_wide = ["square_s_wide","square_s_wide","square_s_wide","square_s_wide","square_s_wide","square_s_wide","square_s_wide","square_s_wide"];
    string[] hrs_blocks_square_s_low = ["square_s_hilonom","low","square_s_low","low_nominal","square_s_low_nom","low","square_s_low","high_nominal_low"];
    string[] hrs_blocks_square_s_nom = ["square_s_hilonom","high_nominal","high_nominal","low_nominal","square_s_low_nom","high_nominal","high_nominal","high_nominal_low"];
    string[] hrs_blocks_square_s_high = ["square_s_hilonom","high_nominal","high_nominal","high","high","high_nominal","high_nominal","high_nominal_low"];
    // Configure spectroscopy
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    // Configure LO and attenuators
    //=============================
    HRS_config_att_lo_fm(band,hrs_mode);
    //
    // Loops on the different configurations of the HRS
    //======================================
    //Calls the 5 modes to be checked
    //Square_S_ultra
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_square_s_ultra[0],hrs_blocks_square_s_ultra[1],hrs_blocks_square_s_ultra[2],hrs_blocks_square_s_ultra[3],hrs_blocks_square_s_ultra[4],hrs_blocks_square_s_ultra[5],hrs_blocks_square_s_ultra[6],hrs_blocks_square_s_ultra[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_square_s_ultra[0],hrs_blocks_square_s_ultra[1],hrs_blocks_square_s_ultra[2],hrs_blocks_square_s_ultra[3],hrs_blocks_square_s_ultra[4],hrs_blocks_square_s_ultra[5],hrs_blocks_square_s_ultra[6],hrs_blocks_square_s_ultra[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Square_S_wide
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_square_s_wide[0],hrs_blocks_square_s_wide[1],hrs_blocks_square_s_wide[2],hrs_blocks_square_s_wide[3],hrs_blocks_square_s_wide[4],hrs_blocks_square_s_wide[5],hrs_blocks_square_s_wide[6],hrs_blocks_square_s_wide[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_square_s_wide[0],hrs_blocks_square_s_wide[1],hrs_blocks_square_s_wide[2],hrs_blocks_square_s_wide[3],hrs_blocks_square_s_wide[4],hrs_blocks_square_s_wide[5],hrs_blocks_square_s_wide[6],hrs_blocks_square_s_wide[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Square_S_low
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_square_s_low[0],hrs_blocks_square_s_low[1],hrs_blocks_square_s_low[2],hrs_blocks_square_s_low[3],hrs_blocks_square_s_low[4],hrs_blocks_square_s_low[5],hrs_blocks_square_s_low[6],hrs_blocks_square_s_low[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_square_s_low[0],hrs_blocks_square_s_low[1],hrs_blocks_square_s_low[2],hrs_blocks_square_s_low[3],hrs_blocks_square_s_low[4],hrs_blocks_square_s_low[5],hrs_blocks_square_s_low[6],hrs_blocks_square_s_low[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Square_S_nominal
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_square_s_nom[0],hrs_blocks_square_s_nom[1],hrs_blocks_square_s_nom[2],hrs_blocks_square_s_nom[3],hrs_blocks_square_s_nom[4],hrs_blocks_square_s_nom[5],hrs_blocks_square_s_nom[6],hrs_blocks_square_s_nom[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_square_s_nom[0],hrs_blocks_square_s_nom[1],hrs_blocks_square_s_nom[2],hrs_blocks_square_s_nom[3],hrs_blocks_square_s_nom[4],hrs_blocks_square_s_nom[5],hrs_blocks_square_s_nom[6],hrs_blocks_square_s_nom[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Square_S_high
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_square_s_high[0],hrs_blocks_square_s_high[1],hrs_blocks_square_s_high[2],hrs_blocks_square_s_high[3],hrs_blocks_square_s_high[4],hrs_blocks_square_s_high[5],hrs_blocks_square_s_high[6],hrs_blocks_square_s_high[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_square_s_high[0],hrs_blocks_square_s_high[1],hrs_blocks_square_s_high[2],hrs_blocks_square_s_high[3],hrs_blocks_square_s_high[4],hrs_blocks_square_s_high[5],hrs_blocks_square_s_high[6],hrs_blocks_square_s_high[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //}
}

/////////////////////////////////////////////////////////////////
// Treatment of calibration parameters for spectral scans
//
// Get frequency steps from long calibration table
/////////////////////////////////////////////////////////////////
// First get index range 
{int,int} procedure GetFIndex {
    string band = "4a"; // HIFI band
    double lo_freq1 = 978200.0 in [480000.0,1950000.0]; // LO frequency
    double lo_freq2 = 979600.0 in [480000.0,1950000.0]; // LO frequency
}{
    // first step: read master file
    string calibfile = slookup("frequencystep_masterfile",band,"tablefile");
    int iindex1 = ibracket(calibfile,"stepnumber",lo_freq1);
    //reduce the upper frequency by epsilon to guarantee bracketing
    double eps = 0.1;
    int iindex2 = ibracket(calibfile,"stepnumber",lo_freq2 - eps);
    // Exception handling
    int tsize = table_size(calibfile);
    if(iindex1 == 0 || iindex1 == tsize - 2) {
        IError("LO frequency " + lo_freq1 + " not covered by available range!");
    }
    if(iindex2 == 0 || iindex2 == tsize - 2) {
        IError("LO frequency " + lo_freq2 + " not covered by available range!");
    } else {
        iindex2 = iindex2 + 1;
    }

    return {iindex1,iindex2};
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure DBS_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size 
    int n_seq = 1; // Number of continuous chop cycles
    int n_load = 0; // additional load measurements in one pointing phase
    int n_loadinterval = 10; // number of nods before a load measurement
    bool end_load = false; // Need for load after each pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    int shiftlength = 10; // Shift of the loop start relative to the pointing
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength + shiftlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            if(shiftlength > 0) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i1 = 1 .. n_load) {
                HIFISlowChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFISlowChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
            // Second phase in first nod position
            // occurs for even cycle numbers
            runintostate = false;
            if(state[2] % 2 == 0) {
                if(end_load) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // A nod slew follows - active HK if not used by load measurement
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 7) {
            // second nod position
            HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i2 = 1 .. n_load) {
                // Use asymmetric scheme now to minimize setup uncertainties
                HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
            // First phase in second nod position
            // occurs for odd cycle numbers
            runintostate = false;
            if(state[2] % 2 == 1) {
                if(end_load) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // A nod slew follows - active HK if not used by load measurement
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
        }
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                // ( Does not occur if end_load is set)
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

//  LCU configuration into NOMINAL mode, procedure
//  Uses best guess D2 voltage from confgilcu table
//  It then uses the new TM page dump TC from the MIB
procedure LCU_config_nominal_w_TMPageDump_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
}{
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //Fetch best guess, and clip to blue max
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    drain2_v = min(result[0]{0},drain2_bluemax);
    //Send command: expect that we have already switched to NOMINAL
    //We set D2 to best guess and wait some time to stabilize chain temperature
    HIFI_Configure_LCU_w_TMPageDump_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,config_lo_delay);
    //
}

//  WBS overall attenuator FM functional test, block
block FT_WBS_att_overall_COMB_fm HIFI 3714 {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //
    //Set zero and comb on
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_ON");
    delay(2);
    //
    //Initial configuration: overall attenuators set to max., individual attenuators to 3
    //H-Polarization
    //
    {double,string}[] result = ConfigurationReader("name_configwbs",["hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result[0]{0});
    string hwh_latchup_s = result[1]{1};
    int hwh_att_band4 = 3;
    int hwh_att_band3 = 3;
    int hwh_att_band2 = 3;
    int hwh_att_band1 = 3;
    int hwh_att_in = 16;
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result[0]{0});
    string hwv_latchup_s = result[1]{1};
    int hwv_att_band4 = 3;
    int hwv_att_band3 = 3;
    int hwv_att_band2 = 3;
    int hwv_att_band1 = 3;
    int hwv_att_in = 16;
    //
    //Loop on overall attenuators
    for(int i = 0 .. 15) {
        // Change the value of the main attenuator
        //========================================
        hwh_att_in = hwh_att_in - 1;
        hwv_att_in = hwv_att_in - 1;
        // Set WBS
        //========
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
    }
    //Set att. to max.
    WBS_config_proc_max_att_w_laser_fm(band,laser_H,laser_V);
    //
}

{int,double,double,double,double,double} obs HifiSScanModeLoadChop {
    string modeName = "load-freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_switch_off = 1 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - Load Chop Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = SScanLoadChop_pre_timing(band,lo_freq,lo_freq_up,redundancy,effResolution,hr1,hr2,wb1,wb2,data_time,data_time_off,n_switch_on,n_switch_off,n_freq_point,n_cycles,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    int n_total = groupnumber * n_cycles;
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,reffreq,pre_timing{0},n_total);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},double,double,double} post_timing = SScanDoubleChop_post_timing(pre_timing{0},telescopetimes,n_freq_point,groupnumber,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,reffreq,post_timing{1},n_total);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    // normal pre_timing values
    int on_inttime = post_timing{1}{0};
    int off_inttime = post_timing{1}{1};
    int n_loadinterval = post_timing{1}{7};
    int n_long_on = post_timing{1}{8};
    int n_long_off = post_timing{1}{9};
    int shiftlength = post_timing{1}{5};
    int initlength = post_timing{1}{14};
    bool final_load = post_timing{1}{12};
    // efficiency parameters
    double avnumchop_on = post_timing{2};
    double avnumchop_off = post_timing{3};
    double tscan = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        SScanLoadChop_commanding(band,reffreq,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,data_time_off,n_switch_on,n_switch_off,n_long_on,n_long_off,n_cycles,n_total,n_loadinterval,final_load,startobs,telescopetimes,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = SScanDoubleChop_deadtimes("lchop",band,reffreq,hr1,hr2,wb1,wb2,n_freq_point,data_time,data_time_off,n_switch_on,n_switch_off,n_long_on,n_long_off,n_cycles,avnumchop_on,avnumchop_off,tscan);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanLoadChop_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,on_inttime,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    SScanDoubleChop_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_freq_point,n_cycles,groupnumber * n_freq_point,avnumchop_on,avnumchop_off,false,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//HIFI-COP-2.1-FTUnp
obs HifiEng_FT_unpumped_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //General parameters in use
    int integ_time = 4;
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(FT_unpumped(band,hrs_mode,integ_time,backend));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            FT_unpumped(band,hrs_mode,integ_time,backend);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//General script to read TM1, TM2,etc, procedure
//Will also clear the error flags
procedure LCU_Read_TM_pages_proc_aot {
}{
    //
    //It will use one single MIB TC, and clear the error flag at end
    Hifi_HIFI_LCU_all_tuning_hk();
    //
    delay(1);
}

// Compute the distance of two vectors in angular coordinates
// General accurate equation
double procedure AngularDistance {
    {double,double} vector1 = {0.0,0.0}; // First vector
    {double,double} vector2 = {0.2,0.2}; // Second vector
}{
    double pideg = 3.14159265 / 180.0;
    double l1 = vector1{0} * pideg;
    double b1 = vector1{1} * pideg;
    double l2 = vector2{0} * pideg;
    double b2 = vector2{1} * pideg;
    double dist = acos(sin(b1) * sin(b2) + cos(b1) * cos(b2) * cos(l1 - l2)) / pideg;

    return dist;
}

////Obsolete block: use procedure instead.
// Move chopper
block Chopper_block_fm HIFI 3206 {
    double chopper = 0.0;
}{
    //    Start_block() ;   
    //    chopper = Check_Chopper_Prime_Redundant(chopper);
    //    Hifi_HIFI_CPR_Chopper_Rot ($BBID,chopper);
    //    Hifi_HIFI_non_periodic_hk_FCU ();		//To get sent voltage
    //    delay (1) ;
    error("Obsolete block. Use Chopper_Rotation_proc_fm instead");
}

//General script to clear error flags and set to nominal, block
block LCU_enable_some_bands_block_fm HIFI 3770 {
    int hl_maskband = 16383; // bit description of bands to be enabled
}{
    //
    //switch to standby
    {double,string}[] result = ConfigurationReader("name_delays",["stdby_delay"],"0",0.0);
    int stdby_delay = iround(result[0]{0});
    Hifi_HIFI_HL_Standby($BBID);
    delay(stdby_delay);
    //Enable all bands
    Hifi_HIFI_Conf_LCU_internal($BBID,hl_maskband,"RESET","RESET",256);
    //LSU_delta_f: 256 = 88mV
    //
}

// Switch HIFI from intermediate to standby I, mode
// Assumed to have switched on and booted ICU when starting this mode
// Will end in standby I mode, i.e. chopper, upconverter, and HBB OFF.
mode HifiManCmd_HIFI_global_switch_on_ops {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
    string chopper_loop = "OPEN" in ["OPEN","CLOSE"]; //chopper loop status
}{
    Mode_status_check_intermediate();
    mois_comment("HIFI global switch ON: successively switch ON subsystems");
    mois_tmcheck("The HIFI ICU must have been switched on and successfully booted before to execute this procedure.");
    StartMode_block_ops();
    //Switch on units
    HIFI_global_switch_on_proc_ops(prime_or_redundant);
    //from moc_1.2: use proc instead of block
    //FPU start-up
    mois_step("Set HIFI FPU to band 0 with chopper loop " + chopper_loop);
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    Init_MSA_ops("0",chopper_loop,0.0,result[0]{0},"ON",prime_or_redundant);
    StopMode_block_ops();
    Mode_status_check_standby_I(chopper_loop,"up",prime_or_redundant);
}

// Load calibration measurement
//
// Most generic version for spectral scans with potentially different 
// frequencies for tuning and timing and retuning switch
//
// We might consider removing zero and comb as well - needs discussion !!!
procedure SScanLoadMeasurement {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double tuning_freq = 978200.0; // LO tuning frequency
    double lo_freq = 978200.0; // LO calibration frequency
    bool retunelo = true; // Whether LO retuning is enabled
    double deltanu = 1.0; // minimum effective resolution of the calibrated data
    int data_time = 4; // time between subsequent data readouts
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
}{
    // Initial computations
    {int,int,bool} calinit = HIFICalInit(band,lo_freq,deltanu,data_time);
    int used_datatime = calinit{0};
    int n_inttime = calinit{1};
    bool retuning = calinit{2} && retunelo;
    // Perform zero and comb measurement
    ZeroCombMeasurement(band,lo_freq,used_datatime,backendreadoutparms);
    // No we perform the actual hot-cold measurement
    // slow_chop_spectroscopy
    int danglingreadout = HIFI_Calibrate_hot_cold(band,lo_freq,used_datatime,n_inttime,backendreadoutparms,false);
    // Retune and another load if we are in HEB bands
    if(retuning) {
        // we have to wait for readout
        delay(danglingreadout);
        // Another LO vector scan at the same frequency for a stable HEB operation
        HIFITuneFreq(band,tuning_freq,false,"");
        danglingreadout = HIFI_Calibrate_hot_cold(band,lo_freq,used_datatime,n_inttime,backendreadoutparms,false);
    }
}

////////////////////////////////////
// DBS raster observing mode - Engineering version with half throw
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiEngHalfThrowDBSRaster {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,100]; // Number of rows in the map
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the raster line
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Engineering - DBS Raster Map halfThrow slowChop",{data_time,0,0,n_switch_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = DBSRaster_pre_timing(nlines,npoints,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    // Check for NoddingInRaster or NoddingOfRaster
    int scansize = pre_timing{10};
    if(scansize > 1) {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,double,double,int,int,int,int,int} tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"half",pre_timing,n_cycles);
        // Dummy call to spacecraft command
        int[] telescopetimes = nodding_of_raster_pointing(false,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double,int,int,int,double,double,int,int,int,int} tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"half",pre_timing,n_cycles);
        telescopetimes = nodding_raster_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSRaster_post_timing(pre_timing,telescopetimes,nlines,npoints,n_switch_on,n_cycles,load_interval,false);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    if(scansize > 1) {
        tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"half",post_timing{1},n_cycles);
        // Call telescope command
        telescopetimes = nodding_of_raster_pointing(true,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"half",post_timing{1},n_cycles);
        telescopetimes = nodding_raster_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        HalfDBSRaster_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,false);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = DBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints,n_cycles,n_seq * imax(n_load,1),tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//Fast chopped hotcold, block
block Hot_cold_fastchop_fm HIFI 3225 {
    string band = "1a";
    int integ_time = 8; //Total integration time for delay computation
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,etc
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast 
    int n_wbs1 = 20;
    int n_hrs_trans = 1;
}{
    //Start_block(); 
    //Rotate chopper: assume we come from M3: no rotation as this is done in the fastchop_spectro
    //Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_hot_ang");
    //Fetch respective chopper angles
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_hot","chop_cold"],band,0.0);
    double chop_hot = result[0]{0};
    double chop_cold = result[1]{0};
    //
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"fastchop",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    HIFI_Spectr_fast_chop_proc_fm(chop_hot,chop_cold,n_wbs1,n_hrs_trans);
    Apply_Fast_Chop_delay(integ_time,1,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// Preliminary LO scan with HRS 0-lag measured, procedure
procedure Proc_LO_scan_w_HRS_lag {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double[] lo_freq_input = [500.0,500.15,0.02]; //Start, end and step lo_freq for the LO scan
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total (co-added) integration time of a phase in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Tune at the first frequency
    LO_tuning_block_fm(band,lo_freq_input[0]);
    //
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_cold_ang");
    //Look at CBB
    //
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration
    int[] res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    //Loop on LO frequencies. It is assumed that the LO is tuned at the initial frequency
    double lo_freq = lo_freq_input[0];
    while(lo_freq <= lo_freq_input[1]) {
        //Set synthesizer to new LO freq.
        LCU_config_nominal_noretune_block_fm(band,lo_freq,lo_freq_input[0]);
        //
        //For bands with diplexer, update diplexer setting
        double band_nb = GetBandCode(band);
        if(band_nb <= 2.0 || band_nb == 5.0) {
            double diplex_H = 0.0;
            //For bands 1, 2 and 5
            double diplex_V = 0.0;
        } else {
            double[] result_dip = Get_Diplexer_setting(band,lo_freq);
            diplex_H = result_dip[0];
            diplex_V = result_dip[1];
            Set_Diplexer_current_block_fm(diplex_H,diplex_V);
        }
        //Take total power spectroscopy
        Spectro_total_power_block_fm(band,res,backend);
        //Increase lo_freq
        lo_freq = lo_freq + lo_freq_input[2];
    }
}

/////////////////////////////////////////////////////////////////
// Redundancy enhancement at the edges
// Return increased redundancy and length of application
{int,double,double} procedure GetEdgeEnhance {
    int redundancy = 4; // Standard redundancy of the scan
    string band = "4a"; // HIFI band
}{
    double[] edge = SpectralScanReader("fscanedge",["bandwidth","edgelength","edgeredun"],band,redundancy);
    int newredun = iround(edge[2]);

    return {newredun,edge[1],edge[0]};
}

////////////////////////////////////
// OTF frequency switch observing mode without baseline calibration
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcFSwitchOTFNoRef {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints = 10 in [1,720]; // Number of data dumps per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period defines number of lines between two loads
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Mapping - OTF Map Frequency Switch noRef",{data_time,0,0,n_switch_on,0,0,0,0,n_cycles,load_interval});
    // Auxiliary routine for API parameter correction
    {double,double,int} mapused = ValidMapSize(band,lo_freq,lineDistance,nlines,stepsize,npoints,2 * data_time * n_switch_on);
    double line_used = mapused{0};
    double scanvelocity = mapused{1};
    int npoints_used = mapused{2};
    // Call first part of the timing computer
    {int,int,int,int,bool,int,int} pre_timing = OTFFSwitchNoRef_pre_timing(nlines,npoints_used,band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,int} tpar = OTFDoubleChopNoRef_telescope(naifid,onPosition,lineDistance,nlines,line_used,scanvelocity,band,lo_freq,n_cycles,pre_timing);
    // Dummy call to spacecraft command
    int[] telescopetimes = line_scan_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,bool,int,int},double,double} post_timing = OTFDoubleChopNoRef_post_timing(pre_timing,telescopetimes,nlines,data_time,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = OTFDoubleChopNoRef_telescope(naifid,onPosition,lineDistance,nlines,line_used,scanvelocity,band,lo_freq,n_cycles,post_timing{1});
    // Call telescope command
    telescopetimes = line_scan_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{0};
    bool end_load_on = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{2};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        OTFFSwitchNoRef_commanding(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,npoints_used * n_switch_on,n_loadinterval,nlines * n_cycles,end_load_on,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SingleChop_deadtimes("fs",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,npoints_used * n_switch_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = FSwitchNoRef_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_switch_on * n_cycles,tscan,tdead);
    // Evaluate performance
    OTFDoubleChopNoRef_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints_used,n_switch_on * n_cycles,true,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

////////////////////////////////////
// OTF frequency switch observing mode
// 
{string,double,double}[] procedure HifiMappingProcFSwitchOTFSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints = 10 in [1,720]; // Number of data dumps per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    {double,double,double,double} phaselengths = FSwitchPhaseLengths(band,lo_freq,effResolution,oneGHzReference);
    // Compute derived quantities
    // Main loop
    int main_phase = iceil(phaselengths{0});
    // How many lines could we do at most?
    int n_linesperscan_guess = main_phase / (2 * datalimit) + 1;
    n_linesperscan_guess = imax(n_linesperscan_guess * n_linesperscan_guess / npoints,1);
    // restrict the scan size
    if(nlines == 1 && n_linesperscan_guess > 1) {
        n_linesperscan_guess = 2;
    } else {
        n_linesperscan_guess = IMultiple(n_linesperscan_guess,nlines);
        n_linesperscan_guess = imin(n_linesperscan_guess,nlines);
    }
    int n_linesperscan_range = 1 - n_linesperscan_guess;
    if(n_linesperscan_range == 0) {
        n_linesperscan_range = 1;
    }
    double n_pointsperscan = double(n_linesperscan * npoints);
    // Compute back
    int int_time_guess = main_phase / iceil(sqrt(n_pointsperscan));
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int n_switch_on_guess = imax(int_time_guess / (2 * data_time_guess),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    data_time_guess = imax(imin(5,int_time_guess / (2 * n_switch_on_guess)),datalimit);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) * 0.67 * sqrt(n_pointsperscan) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)},{"n_linesperscan",double(n_linesperscan_guess),double(n_linesperscan_range)}];

    return retvalues;
}

//PDU switch off of a S/S, procedure
procedure PDU_switch_off_proc_ops {
    string subsystem = "ICU_Prime" in ["ICU_Prime","ICU_Red","LO_Prime","LO_Red","WBS_H","WBS_V","HRS_H","HRS_V"];
}{
    ////HifiIltEgse_PDU_switch_off($BBID,subsystem);	//The TEI command: WILL BE DONE BY SPACON
    mois_spacon("Please power OFF Sub-System " + subsystem);
    //delay(1);
}

//////////////////////////////////////////////////////////
// Stand-by configuration
////////////////////////////
//Set LCU back to standby status without setting any particular LO band, block
//LCU is only set to standby if the band has been switched off
block LCU_standby_block_fm HIFI 3629 {
}{
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_delays",["stdby_delay"],"0",0.0);
    int stdby_delay = iround(result[0]{0});
    //
    //Set in standby mode
    Hifi_HIFI_HL_Standby($BBID);
    delay(stdby_delay);
}

// Laser stabilization time for WBS, procedure
procedure FT_WBS_stabilization_time_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON  
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //
    //Configure WBS
    WBS_config_w_laser_block_fm(band,laser_H,laser_V);
    //Attenuator Tune
    WBS_tune_proc_fm(band);
    //Integration
    Stability_backend_fm(band,n,integ_time,backend,["wb1","wb1"]);
    //Configure spectrometers integration back to default
    Configure_Spectrometer_proc_fm(band,integ_time,["wb1","wb1"],backend);
    //Do zero and COMB
    WBS_calib_fm(band);
    //Set att. to max.
    WBS_config_max_att_w_laser_block_fm(band,laser_H,laser_V);
    //
}

//Get true chopper angles for a chopped observation
{bool,double,double} procedure GetChopVoltages {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    string chop1string = "chop_M3left"; // first chopper position
    string chop2string = "chop_M3right"; // second chopper position
}{
    // get chopper angles for the two positions in prime configuration
    {double,string}[] result = ConfigurationReader("name_confilfpu",[chop1string,chop2string],band,lo_freq);
    double chop1 = result[0]{0};
    double chop2 = result[1]{0};
    //Check prime or redundant status
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant","p_to_r_coeff_0","p_to_r_coeff_1","p_to_r_coeff_2","prime_endstop_min","prime_endstop_max","red_endstop_min","red_endstop_max"],band,lo_freq);
    bool isPrime = result_d[0]{1} == "prime";
    if(isPrime) {
        // check the chopper angle is within the ranges
        double endstop_min = result_d[4]{0};
        double endstop_max = result_d[5]{0};
        if(chop1 > endstop_max || chop1 < endstop_min) {
            IError("The chopper voltage (requested is " + chop1 + " V) in prime" + " mode has to be between " + endstop_min + " and " + endstop_max + " V.");
        }
        if(chop2 > endstop_max || chop2 < endstop_min) {
            IError("The chopper voltage (requested is " + chop2 + " V) in prime" + " mode has to be between " + endstop_min + " and " + endstop_max + " V.");
        }
    } else {
        //Change chopper voltage if necessary   
        chop1 = result_d[3]{0} * pow(chop1,2.0) + result_d[2]{0} * chop1 + result_d[1]{0};
        chop2 = result_d[3]{0} * pow(chop2,2.0) + result_d[2]{0} * chop2 + result_d[1]{0};
        //Now check the chopper angle is within the ranges
        endstop_min = result_d[6]{0};
        endstop_max = result_d[7]{0};
        if(chop1 > endstop_max || chop1 < endstop_min) {
            IError("The chopper voltage (requested is " + chop1 + " V) in redundant" + " mode has to be between " + endstop_min + " and " + endstop_max + " V.");
        }
        if(chop2 > endstop_max || chop2 < endstop_min) {
            IError("The chopper voltage (requested is " + chop2 + " V) in redundant" + " mode has to be between " + endstop_min + " and " + endstop_max + " V.");
        }
    }

    return {isPrime,chop1,chop2};
}

//Configure backends
procedure ConfigureBackend {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
}{
    //HRS configuration:
    //Internal LO relative to IF centre
    double if_centre = 6.0;
    //
    //Resolution mode
    string hrs_mode_h = "hr";
    double[] hrsH_LO = [if_centre + hrs1{2}[0] / 1000.0,if_centre + hrs1{2}[1] / 1000.0,if_centre + hrs1{2}[2] / 1000.0,if_centre + hrs1{2}[3] / 1000.0];
    if(hrs1{0}) {
        // Resolution strings and LO assignment
        if(hrs1{1} == 1) {
            // medium resolution
            hrs_mode_h = "mr";
            hrsH_LO = [if_centre + hrs1{2}[0] / 1000.0,if_centre + hrs1{2}[2] / 1000.0,if_centre + hrs1{2}[3] / 1000.0,if_centre + hrs1{2}[1] / 1000.0];
        }
        if(hrs1{1} == 2) {
            // low resolution
            hrs_mode_h = "lr";
            hrsH_LO = [if_centre + hrs1{2}[0] / 1000.0,if_centre + hrs1{2}[3] / 1000.0,if_centre + hrs1{2}[1] / 1000.0,if_centre + hrs1{2}[2] / 1000.0];
        }
        if(hrs1{1} == 3) {
            // wide-band resolution
            hrs_mode_h = "wb";
        }
    }
    string hrs_mode_v = "hr";
    double[] hrsV_LO = [if_centre + hrs2{2}[0] / 1000.0,if_centre + hrs2{2}[1] / 1000.0,if_centre + hrs2{2}[2] / 1000.0,if_centre + hrs2{2}[3] / 1000.0];
    if(hrs2{0}) {
        // Resolution strings and LO assignment
        if(hrs2{1} == 1) {
            // medium resolution
            hrs_mode_v = "mr";
            hrsV_LO = [if_centre + hrs2{2}[0] / 1000.0,if_centre + hrs2{2}[2] / 1000.0,if_centre + hrs2{2}[3] / 1000.0,if_centre + hrs2{2}[1] / 1000.0];
        }
        if(hrs2{1} == 2) {
            // low resolution
            hrs_mode_v = "lr";
            hrsV_LO = [if_centre + hrs2{2}[0] / 1000.0,if_centre + hrs2{2}[3] / 1000.0,if_centre + hrs2{2}[2] / 1000.0,if_centre + hrs2{2}[2] / 1000.0];
        }
        if(hrs2{1} == 3) {
            // wide-band resolution
            hrs_mode_v = "wb";
        }
    }
    //
    // Apply
    string[] hrs_mode = [hrs_mode_h,hrs_mode_v];
    HRS_config_resol_block_aot(band,hrs_mode);
    HRS_config_att_lo_block_aot(band,hrs_mode,hrsH_LO,hrsV_LO);
    //
    //WBS configuration: set all attenuators to max. Maybe superfluous
    WBS_config_block_aot(band);
    //
}

// Zero measurement with nominal selection
// This should turn into a single command when SCR 743 is solved
int block WBS_Full_Zero HIFI 6003 {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    int data_time = 4; // time between subsequent data readouts
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
}{
    // data rate and read-out time
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int readout = dataparms{0};
    // work-around for SCR 607
    // put the zero switch on
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_ON");
    // Unfortunately we loose 1s here due to the additional commands
    delay(1);
    // send the configure spectroscopy command to configure the measurement
    // returned dead times not needed here
    ConfigureSpectroscopy(data_time,1,"tp",band,lo_freq,backendreadoutparms);
    // set data rates
    non_ess_hk_data_rate(dataparms{1}[2] / 1024.0);
    data_rate(dataparms{1}[0] / 1024.0);
    // execute a total power measurement with the zero switch on
    Hifi_HIFI_Spectr_total_power($BBID);
    delay(data_time);
    // reset data rates
    non_ess_hk_data_rate(dataparms{1}[1] / 1024.0);
    data_rate(0.0);
    // put zero off
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_OFF");
    // We loose again 1s here due to the additional commands
    delay(1);
    // This is reduced due to the SCR 607 overhead in the buidling block
    readout = readout - 1;

    return readout;
}

/////////////////////////////////////////////////////////////////
// Procedure to translate levels into strings
string[] procedure TargetNames {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // reference LO frequency in MHz
    bool retuning = false; // need for WBS retuning
    double[] targetlevels = [1.0,1.0,1.0]; // WBS target levels
}{
    // Get target limits
    double[] limits = CalibrationReader("attenuator_levels",["sscan_max","sscan_min","sscan_high","sscan_normal","sscan_low"],band,lo_freq);
    // Criteria for the table setup
    double halfwidth = limits[2] - limits[4];
    // Output field 
    string[] target = [];
    int nfreq = length(targetlevels);
    // Check for retuning needs
    if(retuning) {
        // Construct table of actual target levels from differences
        double oldtarget = targetlevels[0];
        double step = 0.0;
        int oldindex = 0;
        target[0] = "";
        for(int jjj = 1 .. nfreq - 1) {
            target[jjj] = "";
            step = targetlevels[jjj] - oldtarget;
            if(abs(step) > halfwidth) {
                if(step > 0.0) {
                    target[oldindex] = "sscan_low";
                } else {
                    target[oldindex] = "sscan_high";
                }
                oldtarget = targetlevels[jjj];
                oldindex = jjj;
            }
            // Final tuning
            if(step > 0.0) {
                target[oldindex] = "sscan_low";
            } else {
                target[oldindex] = "sscan_high";
            }
        }
    } else {
        // No retuning needed
        // search again for minimum - use for target level
        double absmin = arraymin(targetlevels);
        if(limits[0] - absmin < halfwidth) {
            target[0] = "sscan_normal";
        } else {
            if(targetlevels[0] > limits[3]) {
                if(targetlevels[0] > limits[2]) {
                    target[0] = "sscan_max";
                } else {
                    target[0] = "sscan_high";
                }
            } else {
                if(targetlevels[0] < limits[4]) {
                    target[0] = "sscan_min";
                } else {
                    target[0] = "sscan_low";
                }
            }
        }
        // Fill the table with empty values
        for(int jjjj = 1 .. nfreq - 1) {
            target[jjjj] = "";
        }
    }
    // table with either a single entry or entries at tuning points

    return target;
}

// Single IV curve procedure: always called from a block !
procedure IVcurve {
    string band = "1a";
    double bias_min = -6.0;
    double bias_max = 6.0;
    int step_count = 131;
    double magnet_current_h = 15.0; // magnet current, set first (mA)
    double magnet_current_v = 15.0; // magnet current, set first (mA)
    double bias_h = 2.2; // bias voltage, set before exit (mV)
    double bias_v = 2.2; // bias voltage, set before exit (mV)
}{
    //In case of band 6 or 7, set first to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,0.0);
        //First go to 4mV
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    int duration_ivcurve = 0;
    double step_duration = 0.1;
    int max_per_command = 40;
    int steps = 0;
    int steps_done = 0;
    double step = Stepsize(bias_min,bias_max,step_count,"hifi_HIF_mxbias_step_V");
    double margin = Stepmargin(bias_min,bias_max,"hifi_HIF_mxbias_step_V");
    int steps_wanted = 1 + iceil((bias_max - bias_min) / step);
    // force the last portion to less than max_per_command:
    if(max_per_command * (steps_wanted / max_per_command) == steps_wanted) {
        steps_wanted = steps_wanted - 1;
    }
    double bias_start = bias_min;
    while(steps_done < steps_wanted) {
        steps = steps_wanted - steps_done;
        if(steps > max_per_command) {
            steps = max_per_command;
        }
        bias_start = bias_min + double(steps_done) * step;
        Hifi_HIFI_FCU_parameter_scan($BBID,steps,1,step_duration,bias_start,bias_start,step + margin,magnet_current_h,magnet_current_v,0.0);
        duration_ivcurve = iceil(double(steps) * step_duration);
        delay(duration_ivcurve + 2);
        steps_done = steps_done + steps;
    }
    //Set back to value on exit
    //In case of band 6 or 7, set first to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,0.0);
        //First go to 4mV
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    Mixerbias(bias_h,bias_v);
}

//Check D2 is within the BLUE ranges
bool procedure Check_D2_vs_BLUE_proc_fm {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band   
    double lo_freq = 500.0; //LO frequency
    double drain2_v = 1.6; //D2_V to compare to blue table
}{
    bool go_ahead = true;
    //Fetch index
    string name_confindex = "name_confindex_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_confindex = "name_confindex_b";
    }
    {double,string}[] result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Fetch D2 blue min and max
    result = ConfigurationReader("name_configlcublue",["blmn1a","blmx1a","blmn1b","blmx1b","blmn2a","blmx2a","blmn2b","blmx2b","blmn3a","blmx3a","blmn3b","blmx3b","blmn4a","blmx4a","blmn4b","blmx4b","blmn5a","blmx5a","blmn5b","blmx5b","blmn6a","blmx6a","blmn6b","blmx6b","blmn7a","blmx7a","blmn7b","blmx7b"],band,double(freq_nx));
    //
    if(band == "1a" && (drain2_v < result[0]{0} || drain2_v > result[1]{0})) {
        go_ahead = false;
    }
    if(band == "1b" && (drain2_v < result[2]{0} || drain2_v > result[3]{0})) {
        go_ahead = false;
    }
    if(band == "2a" && (drain2_v < result[4]{0} || drain2_v > result[5]{0})) {
        go_ahead = false;
    }
    if(band == "2b" && (drain2_v < result[6]{0} || drain2_v > result[7]{0})) {
        go_ahead = false;
    }
    if(band == "3a" && (drain2_v < result[8]{0} || drain2_v > result[9]{0})) {
        go_ahead = false;
    }
    if(band == "3b" && (drain2_v < result[10]{0} || drain2_v > result[11]{0})) {
        go_ahead = false;
    }
    if(band == "4a" && (drain2_v < result[12]{0} || drain2_v > result[13]{0})) {
        go_ahead = false;
    }
    if(band == "4b" && (drain2_v < result[14]{0} || drain2_v > result[15]{0})) {
        go_ahead = false;
    }
    if(band == "5a" && (drain2_v < result[16]{0} || drain2_v > result[17]{0})) {
        go_ahead = false;
    }
    if(band == "5b" && (drain2_v < result[18]{0} || drain2_v > result[19]{0})) {
        go_ahead = false;
    }
    if(band == "6a" && (drain2_v < result[20]{0} || drain2_v > result[21]{0})) {
        go_ahead = false;
    }
    if(band == "6b" && (drain2_v < result[22]{0} || drain2_v > result[23]{0})) {
        go_ahead = false;
    }
    if(band == "7a" && (drain2_v < result[24]{0} || drain2_v > result[25]{0})) {
        go_ahead = false;
    }
    if(band == "7b" && (drain2_v < result[26]{0} || drain2_v > result[27]{0})) {
        go_ahead = false;
    }
    if(go_ahead == false) {
        //debug_print("go_ahead is: " + go_ahead);
        error("D2 voltage not within allowed range for band " + band);
    }

    return go_ahead;
}

//Reduced version: IVC
//HIFI-COP-7.2-LO_FT
procedure LO_FT_IVC_COP_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //General parameters in use
    string multiplier = "ALL";
    int operation_delay = 0;
    //
    double[] cresult_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = cresult_d[0];
    //applies to cold LO
    //
    Measure_LCU_IV_proc_fm(band,multiplier,operation_delay);
    //
}

////////////////////////////////////
// Load chop mode without baseline calibration
// 
// The implementation now assumes that the corresponding Herschel
// pseudo-pointing mode will be available
//
{int,double,double,double,double,double} obs HifiPointProcLoadChopNoRef {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_cycles = 2 in [1,3600]; // number of half load-sky-sky-load cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Single Point - Load Chop noRef",{data_time,0,0,0,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,bool,int,int} pre_timing_f = LoadChopNoRef_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_cycles,load_interval,docommands);
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,double,double,int} tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,pre_timing_f);
    // Dummy call to spacecraft command
    int[] telescopetimes = basic_fine_pointing(false,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,bool,int,int},double,double} post_timing_f = SingleChopNoRef_post_timing(pre_timing_f,telescopetimes);
    // Now the actual observation starts
    // Prepare telescope command
    tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,post_timing_f{1});
    // Call telescope command 
    telescopetimes = basic_fine_pointing(true,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
    // Consistency check
    int totaltime = post_timing_f{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    //////////////////////////////////////////////////////////////////////
    // standard parameters for fine pointing
    int loadlength = post_timing_f{1}{2};
    int n_per_on = post_timing_f{1}{4};
    int n_load_on = post_timing_f{1}{5};
    bool end_load_on = post_timing_f{1}{6};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    //////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        LoadChopNoRef_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_per_on,n_load_on,end_load_on,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // There are no telescope dead times involved in this mode
    {double,double,double} tact = SingleChop_deadtimes("lchop",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_per_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = PositionSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_per_on * (n_load_on + 1),tscan,tdead);
    // Evaluate performance
    SingleChopNoRef_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_per_on * (n_load_on + 1),false,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

{int,double,double,double,double,double} obs HifiMappingModeOTF {
    string modeName = "fly";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,5]; // chunk size given by the data rates and optimum speed
    int n_int_on = 1 in [1,1800]; // Supersamplingfactor
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Mapping - OTF Map Position Switch",{data_time,0,n_int_on,0,n_switch_off,n_linesperscan,0,0,n_cycles,load_interval});
    // Auxiliary routine for API parameter correction
    {double,double,int} mapused = ValidMapSize(band,lo_freq,lineDistance,nlines,stepsize,npoints,data_time * n_int_on);
    double line_used = mapused{0};
    double scanvelocity = mapused{1};
    int npoints_used = mapused{2};
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int} pre_timing = OTFmap_pre_timing(nlines,npoints_used,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_linesperscan,n_switch_off,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,double,double,int,int,int,int,int} tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,pre_timing);
    // Dummy call to spacecraft command
    int[] telescopetimes = line_scan_with_off_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int},double,double} post_timing = OTFmap_post_timing(pre_timing,telescopetimes,data_time,n_linesperscan,n_cycles,load_interval);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,post_timing{1});
    // Call telescope command
    telescopetimes = line_scan_with_off_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int n_pp = post_timing{1}{0};
    int n_scans = post_timing{1}{1};
    int loadlength = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{5};
    double tscan = post_timing{2};
    double tdead = post_timing{3};
    // telescope time
    int slewtime = telescopetimes[6];
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        OTFmap_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,nlines * n_cycles,n_linesperscan,n_switch_off,n_pp,n_loadinterval,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check])
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = OTFmap_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_linesperscan,n_switch_off,n_pp,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = OTFmap_noisecomputer(band,lo_freq,effResolution,oneGHzReference,nlines,npoints_used,n_int_on,n_linesperscan,n_cycles,slewtime,tscan,tact);
    // Evaluate performance
    OTF_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints_used,n_scans,n_cycles,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// HRS attenuator tuning, block
// Both polarizations are treated
// !!! The routine is 1s too short to get rid of all the data.
// It must be externally guaranteed that there is always a dangling
// second without data frames produced !!!
block HRS_tune_block_aot HIFI 6601 {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    Tune_HRS_aot(band);
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure LoadChopNoRef_FCal_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval limited by the data rates
    int n_per_on = 2; // number of half load-sky-sky-load cycles on ON
    int n_load_on = 0; // additional load measurements in ON pointing phase
    bool end_load_on = false; // Need for load after ON pointing phase
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,0]; // Timing of observation from telescope
    int loadlength = 21; // Load duration
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement_FCal(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // ON integration
            HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i1 = 1 .. n_load_on) {
                HIFILoadChopOnIntegration(data_time,n_per_on,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement_FCal(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFILoadChopOnIntegration(data_time,n_per_on,band,lo_freq,rates);
        }
        if(state[0] == 5) {
            delay(readoutdead);
            if(end_load_on) {
                // Perform final load measurement 
                LoadMeasurement_FCal(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            HIFICloseObs();
        }
    }
}

/////////////////////////////////////////////////////////////////
// Spectral scan in load-chop with OFF calibration
// 
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiSScanProcLoadChop {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    bool refSelected = true; // Dummy parameter required by HSPOT
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_switch_off = 1 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - Load Chop Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = SScanLoadChop_pre_timing(band,lo_freq,lo_freq_up,redundancy,effResolution,hr1,hr2,wb1,wb2,data_time,data_time_off,n_switch_on,n_switch_off,n_freq_point,n_cycles,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    int n_total = groupnumber * n_cycles;
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,reffreq,pre_timing{0},n_total);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},double,double,double} post_timing = SScanDoubleChop_post_timing(pre_timing{0},telescopetimes,n_freq_point,groupnumber,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,reffreq,post_timing{1},n_total);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    // normal pre_timing values
    int on_inttime = post_timing{1}{0};
    int off_inttime = post_timing{1}{1};
    int n_loadinterval = post_timing{1}{7};
    int n_long_on = post_timing{1}{8};
    int n_long_off = post_timing{1}{9};
    int shiftlength = post_timing{1}{5};
    int initlength = post_timing{1}{14};
    bool final_load = post_timing{1}{12};
    // efficiency parameters
    double avnumchop_on = post_timing{2};
    double avnumchop_off = post_timing{3};
    double tscan = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        SScanLoadChop_commanding(band,reffreq,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,data_time_off,n_switch_on,n_switch_off,n_long_on,n_long_off,n_cycles,n_total,n_loadinterval,final_load,startobs,telescopetimes,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = SScanDoubleChop_deadtimes("lchop",band,reffreq,hr1,hr2,wb1,wb2,n_freq_point,data_time,data_time_off,n_switch_on,n_switch_off,n_long_on,n_long_off,n_cycles,avnumchop_on,avnumchop_off,tscan);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanLoadChop_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,on_inttime,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    SScanDoubleChop_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_freq_point,n_cycles,groupnumber * n_freq_point,avnumchop_on,avnumchop_off,false,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

////////////////////////////////////////////////////////////////////////
// Radiometric noise from an asymmetric two-phase observation
// This is still to be scaled by a factor 1.0/(B_fluct_A*T_Allan)
double procedure AsymmetricRadioNoise {
    double xa = 0.1; // integration time in phase A relative to Allan time
    double xb = 0.1; // integration time in phase B relative to Allan time
    double resrat = 1.0; // Ratio in the effective resolution B/A
}{
    if(xa > 0.0) {
        double y = 1.0 / xa + 1.0 / (xb * resrat);
    } else {
        // forbid x values <=0
        y = 1.0E11 * (1.0 - xa);
    }

    return y;
}

//////////////////////////////////////////////////////////////////////
// Generic procedure to determine backend parameters for a
//  Configure_spectroscopy command
{int,int,int,int,int[],int[],string} procedure ConfigSpectroscopyBackends {
    /* Integration time */
    int data_time = 4; // Integration time between two data readouts
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands}, WBS1/2 {used, channel windows}
}{
    // The following parameters are hard-wired here as they should never change
    int wbs16bitlimit = 5;
    int wbs16bitrshift1 = 1;
    int wbs16bitrshift2 = 2;
    int wbs24bitrshift0 = 20;
    int wbs24bitrshift1 = 40;
    int wbs24bitrshift2 = 80;
    int hrsrshift0 = 16;
    int hrsrshift1 = 32;
    int hrsrshift2 = 64;
    // Compute transfer mode
    // 16 bit format for short integrations
    if(data_time <= wbs16bitlimit) {
        string packing = "16_bits_format";
        // Right shift depends in data_time
        if(data_time <= wbs16bitrshift1) {
            int wbs_rshift = 1;
        } else {
            if(data_time <= wbs16bitrshift2) {
                wbs_rshift = 2;
            } else {
                wbs_rshift = 3;
            }
        }
        // 24 bit mode for long integrations
    } else {
        packing = "24_bits_format";
        // Right shift to produce valid IF power HK data
        if(data_time <= wbs24bitrshift0) {
            wbs_rshift = 0;
        } else {
            if(data_time <= wbs24bitrshift1) {
                wbs_rshift = 1;
            } else {
                if(data_time <= wbs24bitrshift2) {
                    wbs_rshift = 2;
                } else {
                    wbs_rshift = 3;
                }
            }
        }
    }
    // bit shift for HRS
    if(data_time <= hrsrshift0) {
        int hrs_rshift = 0;
    } else {
        if(data_time <= hrsrshift1) {
            hrs_rshift = 1;
        } else {
            if(data_time <= hrsrshift2) {
                hrs_rshift = 2;
            } else {
                hrs_rshift = 3;
            }
        }
    }
    // Backend selection
    // HRS
    {int,int,int,int} hrssets = HrsSubbandSelection(backendreadoutparms);
    int hrsh_sel = hrssets{0};
    int hrsv_sel = hrssets{1};
    // WBS windows
    // WBS-H
    // Initialize to zero
    int[] wbsh_pars = [0,0,2048,0,4096,0,6144,0];
    if(backendreadoutparms{2}{0}) {
        // Set defined boundaries
        wbsh_pars[0] = backendreadoutparms{2}{1}[0][0] + wbsh_pars[0];
        wbsh_pars[1] = backendreadoutparms{2}{1}[0][1] - backendreadoutparms{2}{1}[0][0];
        wbsh_pars[2] = backendreadoutparms{2}{1}[1][0] + wbsh_pars[2];
        wbsh_pars[3] = backendreadoutparms{2}{1}[1][1] - backendreadoutparms{2}{1}[1][0];
        wbsh_pars[4] = backendreadoutparms{2}{1}[2][0] + wbsh_pars[4];
        wbsh_pars[5] = backendreadoutparms{2}{1}[2][1] - backendreadoutparms{2}{1}[2][0];
        wbsh_pars[6] = backendreadoutparms{2}{1}[3][0] + wbsh_pars[6];
        wbsh_pars[7] = backendreadoutparms{2}{1}[3][1] - backendreadoutparms{2}{1}[3][0];
    }
    // WBS-V
    // Initialize to zero
    int[] wbsv_pars = [0,0,2048,0,4096,0,6144,0];
    if(backendreadoutparms{3}{0}) {
        // Set defined boundaries
        wbsv_pars[0] = backendreadoutparms{3}{1}[0][0] + wbsv_pars[0];
        wbsv_pars[1] = backendreadoutparms{3}{1}[0][1] - backendreadoutparms{3}{1}[0][0];
        wbsv_pars[2] = backendreadoutparms{3}{1}[1][0] + wbsv_pars[2];
        wbsv_pars[3] = backendreadoutparms{3}{1}[1][1] - backendreadoutparms{3}{1}[1][0];
        wbsv_pars[4] = backendreadoutparms{3}{1}[2][0] + wbsv_pars[4];
        wbsv_pars[5] = backendreadoutparms{3}{1}[2][1] - backendreadoutparms{3}{1}[2][0];
        wbsv_pars[6] = backendreadoutparms{3}{1}[3][0] + wbsv_pars[6];
        wbsv_pars[7] = backendreadoutparms{3}{1}[3][1] - backendreadoutparms{3}{1}[3][0];
    }
    //

    return {wbs_rshift,hrs_rshift,hrsh_sel,hrsv_sel,wbsh_pars,wbsv_pars,packing};
}

//Set LCU6La back to standby status, procedure
procedure LCU6La_standby_proc_fm {
    string band = "6a"; // HIFI band
    double lo_freq = 1500.0 in [1410.0,1575.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

// WBS zero, block
block WBS0_fm HIFI 3604 {
    string band = "1a"; // HIFI band
}{
    //Start_block(); 
    //Two options are possible: CUS sequence or automatic OBS command
    //Option1: CUS sequence (has its own delay)
    //WBS0_fm_proc(band);
    //Option2: OBS command
    Hifi_HIFI_WBS_Zero($BBID);
    //Get delay
    {double,string}[] result_d = ConfigurationReader("name_delays",["wbs_zero_delay"],band,0.0);
    int wbs_zero_delay = iround(result_d[0]{0});
    delay(wbs_zero_delay);
}

//Get best guess D2 from look-up table
double procedure Get_BEST_GUESS_D2_proc_fm {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band   
    double lo_freq = 500.0; //LO Frequency
}{
    //Fetch best guess for D2
    string name_configlcutune = "name_configlcu_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlcutune = "name_configlcu_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    //

    return result[0]{0};
}

// Switch HIFI off, procedure
// Prime and Redundancy are both called, regardless of which is effectively used
//
procedure HIFI_global_switch_off_fm {
}{
    //Sequentially notify PDU off then switch off S/S
    //This maybe non-instictive order is due to an ICU bug that
    //screws things up when the ICU tries to get HK from a switched off S/S
    //
    //LOU
    Hifi_HIFI_notify_PDU_status("ON","OFF","ON","ON","ON","ON");
    //HifiIltEgse_PDU_switch_off($BBID,"LO_Prime");	
    //HifiIltEgse_PDU_switch_off($BBID,"LO_Red");	
    //WBS-H
    Hifi_HIFI_notify_PDU_status("ON","OFF","ON","OFF","ON","ON");
    //HifiIltEgse_PDU_switch_off($BBID,"WBS_H");
    //WBS-V
    Hifi_HIFI_notify_PDU_status("ON","OFF","OFF","OFF","ON","ON");
    //HifiIltEgse_PDU_switch_off($BBID,"WBS_V");
    //HRS-H
    Hifi_HIFI_notify_PDU_status("ON","OFF","OFF","OFF","ON","OFF");
    //HifiIltEgse_PDU_switch_off($BBID,"HRS_H");
    //HRS-V
    Hifi_HIFI_notify_PDU_status("ON","OFF","ON","OFF","OFF","OFF");
    //HifiIltEgse_PDU_switch_off($BBID,"HRS_V");
    //ICU
    Hifi_HIFI_notify_PDU_status("OFF","OFF","OFF","OFF","OFF","OFF");
    //HifiIltEgse_PDU_switch_off($BBID,"ICU_Prime");
    //HifiIltEgse_PDU_switch_off($BBID,"ICU_Red");
    //At that stage, the instrument is idle...
}

// Magnet current scan, fast, procedure.
// Mixer current as a function of magnet current.
procedure Magnet_scan_fast_proc {
    string band = "1a"; // HIFI band		//Setting file
    double magnet_current_min_h = -10.0; //minimum magnet current H
    double magnet_current_max_h = 15.0; //maximum magnet current H
    double magnet_current_min_v = -10.0; //minimum magnet current V
    double magnet_current_max_v = 15.0; //maximum magnet current V
    int n_steps = 100; //number of steps
    double lo_freq = 522.0; //LO frequency
}{
    //
    Magnet_scan_fast_fm(band,magnet_current_min_h,magnet_current_max_h,magnet_current_min_v,magnet_current_max_v,n_steps,lo_freq);
    //Back to nominal values
    if(band != "0") {
        {double,string}[] result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
    }
    if(band == "0") {
        result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v","magnet_standby_h","magnet_standby_v","bias_standby_h","bias_standby_v"],band,0.0);
    }
    //First set magnet to maximum to avoid hysteresis
    double magnetcurrent_max_h = result[0]{0};
    double magnetcurrent_max_v = result[1]{0};
    Set_Magnet_current_block_fm(magnetcurrent_max_h,magnetcurrent_max_v);
    //Nominal values
    result = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v","norm_bias_h","norm_bias_v"],band,lo_freq);
    Set_Magnet_current_block_fm(result[0]{0},result[1]{0});
    //Also set bias voltages back to nominal values
    Mixerbias_block_fm(result[2]{0},result[3]{0});
}

// Standing wave analysis, mode
// For COP, we observe mostly sky-CBB, and sometimes sky-HBB and sky-sky pairs
//HIFI-COP-3-StWv1
obs HifiEng_standing_wave_noretune_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int freq_index = 1; //The frequency index to consider: 1 to 4
    string los_code = "sc" in ["sc","sh","ss"]; //The line-of-sight code: sc (sky-CBB), sh (sky-HBB), ss (sky-sky)
}{
    //General parameters in use
    string backend = "both";
    string[] hrs_mode = ["mr","mr"];
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Standing_wave_noretune_COP_proc_ops(band,backend,hrs_mode,freq_index,los_code));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Standing_wave_noretune_COP_proc_ops(band,backend,hrs_mode,freq_index,los_code);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// Perform frequency-switch integration at OFF position ON-OFF-OFF-ON...
block HIFIFSwitchOffIntegration HIFI 6039 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_fswitch_proc_aot(data_time,n_cycle,band,lo_freq,rates);
}

//  WBS overall attenuator FM functional test, block
//  Done for laser1
block FT_WBS_att_individual_fm HIFI 3707 {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //
    //Set zero and comb off
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_OFF");
    delay(2);
    //
    //Initial configuration: overall attenuators set to 0, individual attenuators to max.
    //H-Polarization
    //
    {double,string}[] result = ConfigurationReader("name_configwbs",["hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result[0]{0});
    string hwh_latchup_s = result[1]{1};
    int hwh_att_band4 = 8;
    int hwh_att_band3 = 8;
    int hwh_att_band2 = 8;
    int hwh_att_band1 = 8;
    int hwh_att_in = 0;
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result[0]{0});
    string hwv_latchup_s = result[1]{1};
    int hwv_att_band4 = 8;
    int hwv_att_band3 = 8;
    int hwv_att_band2 = 8;
    int hwv_att_band1 = 8;
    int hwv_att_in = 0;
    //       
    //Loop on overall attenuators
    for(int i = 0 .. 7) {
        // Change the value of the individual attenuators
        //===============================================
        hwh_att_band4 = hwh_att_band4 - 1;
        hwh_att_band3 = hwh_att_band3 - 1;
        hwh_att_band2 = hwh_att_band2 - 1;
        hwh_att_band1 = hwh_att_band1 - 1;
        hwv_att_band4 = hwv_att_band4 - 1;
        hwv_att_band3 = hwv_att_band3 - 1;
        hwv_att_band2 = hwv_att_band2 - 1;
        hwv_att_band1 = hwv_att_band1 - 1;
        // Set WBS
        //========
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
    }
    //Set att. to max.
    WBS_config_proc_max_att_w_laser_fm(band,laser_H,laser_V);
    //
}

//HIFI LO tuning with choice of mixer to be used, block
//Target current is read from look-up table
block LO_tuning_w_mixerchoice_block_fm HIFI 3675 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string mixer_polarization = "H" in ["H","V","B"]; //The polarization to be used for the tuning
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    //
    //Get target mixer current
    {double,string}[] result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double middle_d2 = result[0]{0};
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    //
    //delay(5);	//to settle at this value
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//
// Magnet current scan, fast, block.
// Mixer current as a function of magnet current.
block Magnet_scan_fast_fm HIFI 3270 {
    string band = "1a"; // HIFI band
    double magnet_current_min_h = -15.0; //minimum magnet current H
    double magnet_current_max_h = 10.0; //maximum magnet current H
    double magnet_current_min_v = -15.0; //minimum magnet current V
    double magnet_current_max_v = 10.0; //maximum magnet current V
    int n_steps = 100; //number of steps
    double lo_freq = 522.0; //LO frequency
}{
    Start_block();
    {double,string}[] result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
    double magnetcurrent_max_h = result[0]{0};
    double magnetcurrent_max_v = result[1]{0};
    //We use special biasing to evidence the minima in the magnet scan
    result = ConfigurationReader("name_confilmix",["bias4magn_h","bias4magn_v"],band,lo_freq);
    double bias_h = result[0]{0};
    double bias_v = result[1]{0};
    Mixerbias(bias_h,bias_v);
    //
    int steps = 0;
    int steps_done = 0;
    double step_duration = 0.1;
    int steps_wanted = n_steps;
    if(steps_wanted < 1) {
        steps_wanted = 1;
    }
    double magnet_current_h = 0.0;
    double stepsize_h = 0.0;
    double magnet_current_v = 0.0;
    double stepsize_v = 0.0;
    if(steps_wanted > 1) {
        stepsize_h = (magnet_current_max_h - magnet_current_min_h) / (double(steps_wanted) - 1.0);
        stepsize_v = (magnet_current_max_v - magnet_current_min_v) / (double(steps_wanted) - 1.0);
    }
    //
    //Set magnet to maximum to avoid hysteresis
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnetcurrent_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnetcurrent_max_v);
    delay(1);
    //
    //Start scan: from max. to min. magnet downward.
    while(steps_done < steps_wanted) {
        steps = steps_wanted - steps_done;
        if(steps > n_steps) {
            steps = n_steps;
        }
        magnet_current_h = magnet_current_max_h - double(steps_done) * stepsize_h;
        magnet_current_v = magnet_current_max_v - double(steps_done) * stepsize_v;
        Hifi_HIFI_FCU_parameter_scan($BBID,1,1,step_duration,bias_h,bias_v,0.0,magnet_current_h,magnet_current_v,0.0);
        //Sets magnet current
        delay(2);
        steps_done = steps_done + 1;
    }
}

//  LCU1a configuration and tuning, procedure
procedure LCU1a_config_tune_proc_fm {
    string band = "1a"; // HIFI band
    double lo_freq = 500.0 in [488.0,552.0]; //LO frequency
    double drain_2_factor = 100.0; //Percentage factor of the targetted drain voltage
}{
    error("This module is obsolete: use LO_tuning_block_fm  instead");
}

// Configuration for slow-chop integration
block HIFIConfigureSlowChopIntegration HIFI 6030 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used, channel windows}
}{
    // Call procedure doing the work
    ConfigureSpectroscopy(data_time,2 * n_cycle,"chop",band,lo_freq,backendreadoutparms);
}

//Readback of LCU safety table, block
block LcuSafetyTableReadback_ops HIFI 7901 {
}{
    StartBlock_ops();
    //
    for(int band = 1 .. 7) {
        for(int fIndex = 0 .. 31) {
            Hifi_HIFI_non_periodic_hk_LCU(fIndex,"channel_" + band + "a");
            delay(2);
            Hifi_HIFI_non_periodic_hk_LCU(fIndex,"channel_" + band + "b");
            delay(2);
        }
    }
}

// Special configuration and data taking for FSW response time
block FSW_Response_time_block_fm HIFI 3688 {
    string hrs_polar = "H" in ["H","V","B"]; //HRS polarizations in use
    int[] del_wbs_param = [10,200,10,100]; //starting, ending and step value for del_wbs
}{
    //
    //Additional "constant" parameters
    {double,string}[] result = ConfigurationReader("name_delays",["add_hrs","add_wbs","add_jitter","wbs_init","wbs_chunksize","tacc_add","hrs_phase"],"0",0.0);
    int add_hrs = iround(result[0]{0});
    int add_wbs = iround(result[1]{0});
    int wbs_init = iround(result[3]{0});
    int wbs_chunksize = iround(result[4]{0});
    int tacc_add = iround(result[5]{0});
    int hrs_phase = iround(result[6]{0});
    // HRS standard phase length
    //
    // Get fixed parameters from configuration and calibration files
    // Command jitter time is the default delay 
    result = ConfigurationReader("name_delays",["add_jitter"],"0",0.0);
    int add_jitter = iround(result[0]{0});
    //Fetch default parameters
    result = ConfigurationReader("name_confilspec",["del_hrs","del_wbs","t_acc_wbs","t_acc_hrs","n_wbs_integr","n_hrs_integr","r_hrs","wbsh_offset1","wbsh_width1","wbsh_offset2","wbsh_width2","wbsh_offset3","wbsh_width3","wbsh_offset4","wbsh_width4","wbsv_offset1","wbsv_width1","wbsv_offset2","wbsv_width2","wbsv_offset3","wbsv_width3","wbsv_offset4","wbsv_width4","hrs_rshift","wbs_rshift","hrsh_sel","hrsv_sel","wbs_packing"],"0",0.0);
    //
    // WBS delta time 
    int del_wbs = del_wbs_param[0];
    // HRS delta time - should be zero
    int del_hrs = add_jitter;
    //Fixed integration time for this test
    int n_data = 4;
    int data_time = 1;
    //Integration time for one phase if only one HRS polar
    if(hrs_polar == "B") {
        data_time = 2;
    }
    // Split total integration time
    int tint = data_time * n_data * 1000;
    // Accumulation time
    // Ignores that total power can be slightly more efficient
    int t_acc_wbs = (tint - wbs_init) / n_data - add_wbs - add_jitter - del_wbs;
    // discretize in 10ms chunks
    int nchunk = (t_acc_wbs - tacc_add) / wbs_chunksize;
    t_acc_wbs = nchunk * wbs_chunksize + tacc_add;
    // No WBS addition in ICU
    int n_wbs_integr = 1;
    int n_wbs_start = n_data;
    // HRS
    int hrs_fullphase = hrs_phase + del_hrs + add_hrs;
    int r_hrs = (t_acc_wbs + hrs_fullphase - add_jitter) / hrs_fullphase;
    int t_acc_hrs = iceil(min(double(del_wbs_param[0]),double((t_acc_wbs - add_jitter) / r_hrs - del_hrs - add_hrs)));
    // for n_wbs_integr=1 identical to r_hrs
    int n_hrs_integr = r_hrs;
    //No WBS
    int wbsh_offset1 = 0;
    int wbsh_width1 = 0;
    int wbsh_offset2 = 0;
    int wbsh_width2 = 0;
    int wbsh_offset3 = 0;
    int wbsh_width3 = 0;
    int wbsh_offset4 = 0;
    int wbsh_width4 = 0;
    int wbsv_offset1 = 0;
    int wbsv_width1 = 0;
    int wbsv_offset2 = 0;
    int wbsv_width2 = 0;
    int wbsv_offset3 = 0;
    int wbsv_width3 = 0;
    int wbsv_offset4 = 0;
    int wbsv_width4 = 0;
    int hrs_rshift = 0;
    int wbs_rshift = iround(result[24]{0});
    int hrsh_sel = 0;
    int hrsv_sel = 0;
    if(hrs_polar == "H" || hrs_polar == "B") {
        hrsh_sel = 255;
    }
    if(hrs_polar == "V" || hrs_polar == "B") {
        hrsv_sel = 255;
    }
    string wbs_packing = result[27]{1};
    //
    //Now loop on del_wbs and trigger FSW spectro
    int step = del_wbs_param[2];
    while(del_wbs <= del_wbs_param[1]) {
        //
        //Configure integration to be done
        Hifi_HIFI_config_spectroscopy($BBID,n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,wbsh_offset1,wbsh_width1,wbsh_offset2,wbsh_width2,wbsh_offset3,wbsh_width3,wbsh_offset4,wbsh_width4,wbsv_offset1,wbsv_width1,wbsv_offset2,wbsv_width2,wbsv_offset3,wbsv_width3,wbsv_offset4,wbsv_width4,hrs_rshift,wbs_rshift,hrsh_sel,hrsv_sel,wbs_packing);
        //
        //Take spectrum
        Hifi_HIFI_Spectr_freq_switch($BBID);
        //Compute delay
        result = ConfigurationReader("name_delays",["wbs_transfer_delay"],"0",0.0);
        //
        int wbs_packet_transfer_time = iround(result[0]{0});
        int delay_fsw = n_wbs_start * data_time + wbs_packet_transfer_time / 1000;
        //debug_print("Total power delay: " + delay_total_power + " sec");
        //
        //Apply delay
        delay(delay_fsw);
        //
        //Increase step
        del_wbs = del_wbs + step;
        //Re-adjust spectrometer integration times
        //WBS
        t_acc_wbs = (tint - wbs_init) / n_data - add_wbs - add_jitter - del_wbs;
        // discretize in 10ms chunks
        nchunk = (t_acc_wbs - tacc_add) / wbs_chunksize;
        t_acc_wbs = nchunk * wbs_chunksize + tacc_add;
        //HRS
        r_hrs = (t_acc_wbs + hrs_fullphase - add_jitter) / hrs_fullphase;
        t_acc_hrs = iceil(min(double(del_wbs_param[0]),double((t_acc_wbs - add_jitter) / r_hrs - del_hrs - add_hrs)));
    }
}

//HIFI-COP-2.1-DipCal2
obs HifiEng_Diplexer_calibration_hotcold_COP {
    string band = "3" in ["3","4","6","7"]; // HIFI mixer band
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Diplexer_calibration_hotcold_COP_proc_ops(band));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Diplexer_calibration_hotcold_COP_proc_ops(band);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//HIFI LO tuning only for M1 investigation in 7b, block
//Target current is read from look-up table
block LO_tuning_w_M1_block_fm HIFI 3716 {
    string band = "7b"; // HIFI band
    double lo_freq = 1890.0; //LO frequency
    double m1 = -5.0; //M1 multiplier voltage
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    string mixer_polarization = result[0]{1};
    //
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = m1;
    //result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    //The automatic tuning shall use the min of the nominal best-guess and Vd2max - 100mV
    double middle_d2 = min(result[0]{0},drain2_bluemax - 0.1);
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * middle_d2;
    //drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    if(band == "3b") {
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum);
        //Send command: specific to M3 in 3b
        delay(config_lo_delay);
        //
        //Additional read of TM pages
        LCU_Read_TM_pages_proc_fm();
    } else {
        //
        //General command
        HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    }
    //
    //delay(5);	//to settle at this value
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the observing mode
{double,double,double,double,double} procedure FSwitch_noisecomputer {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    int on_inttime = 16; // Integration time per ON phase
    int off_inttime = 16; // Integration time per OFF phase
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF calibration cycles
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double,double,double} tact = {10.0,4.9,4.9,0.05,0.05}; // Field of actual dead and integration times
}{
    double tdead = tact{0};
    // Average total dead time in one scan
    double inttimeperonphase = tact{1};
    // Actual integration time in ON phase
    double inttimeperoffphase = tact{2};
    // Actual integration time in OFF phase
    double deadtimeperonphase = tact{3};
    // Dead time per switch phase on ON
    // Get parameters which are needed
    double tsys = InterpolateTsys(band,lo_freq);
    double eta_mb = InterpolateCoupling(band,lo_freq);
    double[] gssb = InterpolateGssb(band,lo_freq);
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double allan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // Differential Allan variance
    allanparms = InterpolateSpecFSwitchAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double dalpha = allanparms[1];
    binningexp = 1.0 / allanparms[2];
    double dallan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double dallan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // resolution of OFF phase
    double sw_resolution = GetFSwitchSWResolution(band,lo_freq);
    double sw_resolution_lores = max(eff_resolution{1},sw_resolution);
    double sw_resolution_hires = max(eff_resolution{0},sw_resolution);
    // Compute the relative noise for the detailed timing
    double on_int = double(on_inttime);
    double off_int = double(off_inttime);
    // The dead time per switch might deviate between ON and OFF - ignored
    double deadtimeperswitch = deadtimeperonphase;
    // Get actual noise
    // This is returned twice: for both limiting resolutions
    double systemnoise_lores = DoubleDifferenceNoise(inttimeperonphase / allan_time_lores,[inttimeperoffphase / inttimeperonphase,sw_resolution_lores / eff_resolution{1},on_int / allan_time_lores,off_int / allan_time_lores,deadtimeperswitch / allan_time_lores,tdead / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    double systemnoise_hires = DoubleDifferenceNoise(inttimeperonphase / allan_time_hires,[inttimeperoffphase / inttimeperonphase,sw_resolution_hires / eff_resolution{0},on_int / allan_time_hires,off_int / allan_time_hires,deadtimeperswitch / allan_time_hires,tdead / allan_time_hires,alpha,dallan_time_hires / allan_time_hires,dalpha]);
    double noiseratio = DoubleDifferenceNoiseRatio(inttimeperonphase / allan_time_lores,[inttimeperoffphase / inttimeperonphase,sw_resolution_lores / eff_resolution{1},on_int / allan_time_lores,off_int / allan_time_lores,deadtimeperswitch / allan_time_lores,tdead / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    // Compute total double sideband noise 
    // Correct for signal in both pases
    double dsbnoise_lores = tsys * sqrt(systemnoise_lores / (eff_resolution{1} * 2000000.0 * double(n_cycles) * tscan));
    double dsbnoise_hires = tsys * sqrt(systemnoise_hires / (eff_resolution{0} * 2000000.0 * double(n_cycles) * tscan));
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Get single sideband noise equivalent
    double usbnoise_lores = dsbnoise_lores / gssb[0];
    double usbnoise_hires = dsbnoise_hires / gssb[0];
    double lsbnoise_lores = dsbnoise_lores / gssb[1];
    double lsbnoise_hires = dsbnoise_hires / gssb[1];
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiseratio};
}

//TM check when in standby II
procedure Mode_status_check_standby_II {
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
    string chopper_loop = "OPEN" in ["OPEN","CLOSE"]; //chopper loop status
    string sequence_order = "up" in ["down","up"]; //order in which sequence is done
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_comment("Checking instrument status in standby II mode");
    //General checks: not applicable here: S/S should all be on here
    //FCU checks
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],"0",0.0);
    double calibcurrent = result_d[0]{0};
    //Getting in band0 is only new when coming from primary
    if(sequence_order == "down") {
        mois_tmcheck("Check that parameter HF_DH1_MXBAND and HF_DV1_MXBAND are both 0");
    }
    //Checking if HBB is on important at any standby or primary stage
    mois_tmcheck("Check that parameter HF_APR_CS_C is set to " + calibcurrent + " mA. If not, you can proceed but need to inform HIFI ICC.");
    //Chopper voltage
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    result_d = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    if(sequence_order == "down") {
        mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to " + result_d[0]{0});
        //Chopper loop status should always be monitored
        mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to " + chopper_loop);
    }
    //
    //WBS checks: although only lasers are changed, the whole configuration command is called
    result_d = ConfigurationReader("name_configwbs",["hwh_latchup_s","hwv_latchup_s"],"0",0.0);
    string hwh_latchup_s = "Low";
    if(result_d[0]{1} == "Level2") {
        hwh_latchup_s = "High";
    }
    string hwv_latchup_s = "Low";
    if(result_d[1]{1} == "Level2") {
        hwv_latchup_s = "High";
    }
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwv_laser2_s = "ON";
    }
    //
    mois_tmcheck("Check that parameters HWH_Laser1_S, HWH_Laser2_S, HWV_Laser1_S and HWV_Laser2_S are respectively " + hwh_laser1_s + ", " + hwh_laser2_s + ", " + hwv_laser1_s + " and " + hwv_laser2_s);
    mois_tmcheck("Check that both parameters HWH_Zero_S and HWV_Zero_S are ON");
    mois_tmcheck("Check that both parameters HWH_Comb_S and HWV_Comb_S are OFF");
    mois_tmcheck("Check that parameters HWH_LUP_level_S and HWV_LUP_level_S are " + hwh_latchup_s + " and " + hwv_latchup_s + " respectively");
    mois_tmcheck("Check that parameter HWH_IN_ATT is set to 15, and parameters HWH_Band_1_ATT, HWH_Band_2_ATT, HWH_Band_3_ATT, HWH_Band_4_ATT are set to 7");
    mois_tmcheck("Check that parameter HWV_IN_ATT is set to 15, and parameters HWV_Band_1_ATT, HWV_Band_2_ATT, HWV_Band_3_ATT, HWV_Band_4_ATT are set to 7");
    //HRS Checks: HRS only modified if from primary to standbyII
    if(sequence_order == "down") {
        // Fetch HRS configuration parameters
        //===================================
        //H-polar
        string hrs_filename_h = "name_confighrs_wb";
        {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],"0",0.0);
        string hrs_polarization_h = result[0]{1};
        double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
        //V-polar
        string hrs_filename_v = "name_confighrs_wb";
        result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],"0",0.0);
        string hrs_polarization_v = result[0]{1};
        double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
        //
        mois_tmcheck("Check that parameters HRH_1U_ATT, HRH_1L_ATT, HRH_2U_ATT, HRH_2L_ATT, HRH_3U_ATT, HRH_3L_ATT, HRH_4U_ATT and HRH_4L_ATT are set to 15.5");
        mois_tmcheck("Check that parameters HRV_1U_ATT, HRV_1L_ATT, HRV_2U_ATT, HRV_2L_ATT, HRV_3U_ATT, HRV_3L_ATT, HRV_4U_ATT and HRV_4L_ATT are set to 15.5");
        mois_tmcheck("Check that parameters HRH_LOCK_LO1_S, HRH_LOCK_LO2_S, HRH_LOCK_LO3_S, HRH_LOCK_LO4_S, HRH_LOCK_LO5_S, HRH_LOCK_LO6_S, and HRH_LOCK_LO7_S are all Locked");
        mois_tmcheck("Check that parameters HRV_LOCK_LO1_S, HRV_LOCK_LO2_S, HRV_LOCK_LO3_S, HRV_LOCK_LO4_S, HRV_LOCK_LO5_S, HRV_LOCK_LO6_S, and HRV_LOCK_LO7_S are all Locked");
        Check_HRS_LO_proc_ops(["wb","wb"],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    }
    //LOU Checks:
    if(sequence_order == "down") {
        mois_tmcheck("Check that parameter HL_MODE_S is standby");
        mois_tmcheck("Check that parameter HL_Channel_S is Off");
    }
}

// Switch on LO band - version using the slew towards a fixed point for
// stabilization
// assumes HIFI is prime and LO is in nominal mode
obs HifiEngSwitchonLO_inslew {
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    bool robust = true; // whether the subsequent AOR is chopped+spectroscopic
}{
    // First part - determine timing and telescope parameters
    // Fixed parameters
    int data_time = 4;
    // Data readout period
    {double,double} eff_resolution = {1.1,1.1};
    // Native WBS resolution as goal resolution
    // Get reference frequency
    string keyfreqname = "keyfreq";
    //this is for warm LO operations
    // "keyfreq" for cold LO operations
    // "keyfreq_dummy"  for dummy LO operations
    // "midfreq" old approach
    double[] result_d = CalibrationReader("name_keyfreq",[keyfreqname],band,0.0);
    double lo_freq = result_d[0] * 1000.0;
    // Backend settings
    // standard routine from spectral scans
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,2,true,true,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    // Call specific pre_timing computer
    {int,int,int,int,int,int} pre_timing = SwitchOnLoadChop_pre_timing(band,lo_freq,eff_resolution,hr1,hr2,wb1,wb2,data_time,robust);
    // get parameters for fine pointing
    int totaltime = pre_timing{0};
    // total duration for check
    int on_pointing = pre_timing{1};
    // Pointing time
    int initlength = pre_timing{2};
    // Initial setup time
    int dangling = pre_timing{3};
    // Final load measurement
    int n_cycles1 = pre_timing{4};
    // Number of chop cycles before retuning
    int n_cycles = pre_timing{5};
    // Number of chop cycles after retuning
    // In the slew mode we rearrange the times
    initlength = initlength + on_pointing;
    on_pointing = dangling;
    dangling = 0;
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    // standard timing parameter list to reuse Fine_telescope procedure
    {int,int,int,int,int,int,bool,int,int} std_timing = {on_pointing,on_pointing,on_pointing,0,0,0,false,initlength,dangling};
    {int,int,int,string,int,double,double,double,double,int} tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,std_timing);
    // Call telescope command 
    int[] telescopetimes = basic_fine_pointing(true,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
}{
    // Second part - instrument commanding
    // Get final deceleration time from the telescope section
    int tend = telescopetimes[2];
    totaltime = totaltime + tend;
    // Backend settings
    // Create a composite readout structure
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hr1{0},hr1{1},hr1{3}},{hr2{0},hr2{1},hr2{3}},wb1,wb2};
    // additional fixed parameters like in standard observing modes
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    //////////////////
    // Instrument commanding
    sync();
    int startobs = time();
    // use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
            // Actual switch-on
            // The switch will always be done at the same frequency
            LCU_switchon_proc_aot(band,lo_freq / 1000.0);
            // Initial setup and LO tuning
            Init_Mixing_proc_aot(band,lo_freq / 1000.0);
            //Deflux will do be done for bands 1 to 4
            Deflux_SingleBand_proc_aot(band,lo_freq / 1000.0);
            // Standard backend tuning
            string target_name = "normal";
            // Name of target level
            if(wb1{0} || wb2{0}) {
                WBS_attenuators_block(band,lo_freq / 1000.0,target_name,false);
            }
            if(hr1{0} || hr2{0}) {
                HRS_tune_block_aot(band);
            }
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            // ON integration - long hot-cold measurement
            if(n_cycles1 > 0) {
                HIFI_Calibrate_hot_cold(band,lo_freq,data_time,2 * n_cycles1,backendreadoutparms,false);
                HIFITuneFreq(band,lo_freq,false,"");
            }
            HIFI_Calibrate_hot_cold(band,lo_freq,data_time,2 * n_cycles,backendreadoutparms,false);
        }
        if(state[0] == 3) {
            delay(readoutdead);
            // Perform final load measurement 
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            HIFICloseObs();
        }
    }
    // Finalize observations
    // consistency check
    int timeTaken = time() - startobs;
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    // Noise estimates could be easily added, but are not done here
    // in the current implementation
}

// Chopper calibration for a given mixer band, procedure
procedure Chopper_calibration_proc_fm {
    int band = 1 in [1,7]; // HIFI mixer band
    int integ_time = 4; //Integration time PER PHASE for the slowchop measurement  
    bool shutter_used = false;
    bool sky = true; //whether or not we scan over M3 area
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3
}{
    string chopmode = "slowchop";
    //close shutter if necessary
    if(shutter_used) {
        //Shutter_rotate_proc_fm("closed");
    }
    //Tune backends on the hot load
    Chopper_Rotation_block_fm("" + band + "a","chop_M3_ang","chop_hot_ang");
    //Configure and tune backends
    WBS_calib_fm("" + band + "a");
    WBS_tune_proc_fm("" + band + "a");
    HRS_tune_block_fm("" + band + "a");
    //The chopper scan is done in slowchop mode to avoid short term instabilities
    int[] res = Configure_Spectrometer_hc_slow_chop_proc_fm("" + band + "a",integ_time * 2,["wb1","wb1"],"both");
    int total_time = res[0] * res[1];
    int n_wbs1 = 0;
    //we use the slowchop mode
    int n_hrs_trans = 0;
    //we use the slowchop mode
    double chop_phase = 1.0;
    //we use the slowchop mode
    //
    //If HEB bands, chop faster with fastchop: 1Hz
    if(band > 5) {
        chop_phase = 0.5;
        res = Configure_Spectrometer_fast_chop_proc_fm("" + band + "a",integ_time * 2,chop_phase,["wb1","wb1"],"both");
        total_time = iceil(chop_phase * double(res[1] * res[2]));
        n_wbs1 = res[2];
        n_hrs_trans = res[3];
        chopmode = "fastchop";
    }
    //
    //Get voltages for start and end positions, and number of steps
    {double,string}[] result_d = ConfigurationReader("name_confilchopcalib",["chop_start","chop_end","chop_nstep","chop_start_sky","chop_end_sky","chop_nstep_sky"],"" + band + "a",double(band));
    double chopper_pos_min = result_d[0]{0};
    double chopper_pos_max = result_d[1]{0};
    int n_steps = iround(result_d[2]{0});
    if(sky) {
        chopper_pos_min = result_d[3]{0};
        chopper_pos_max = result_d[4]{0};
        n_steps = iround(result_d[5]{0});
    }
    //
    Chopper_scan_fm("" + band + "a",chopper_pos_min,chopper_pos_max,n_steps,total_time,"both",chopmode,n_wbs1,n_hrs_trans,false,shutter_used,hrs_mode,chop_phase);
}

{int,double,double,double,double,double} obs HifiSScanModeFastDBS {
    string modeName = "freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - DBS fastChop",{data_time,0,n_switch_on,n_int_on,0,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time / 2);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,int,int,int,bool,int,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = FastSScanDBS_pre_timing(band,lo_freq,lo_freq_up,redundancy,effResolution,hr1,hr2,wb1,wb2,data_time,n_int_on,n_switch_on,n_freq_point,n_cycles,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    int n_total = groupnumber * n_cycles;
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = DBS_telescope(naifid,onPosition,band,reffreq,"",pre_timing{0},n_total);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},double,double,double} post_timing = SScanDBS_post_timing(pre_timing{0},telescopetimes,n_freq_point,groupnumber,n_cycles,true);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,reffreq,"",post_timing{1},n_total);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    // normal pre_timing values
    int n_loadinterval = post_timing{1}{7};
    int n_bchop = post_timing{1}{8};
    int shiftlength = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    double avnumchop = post_timing{2};
    // efficiency parameters
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FastSScanDBS_commanding(band,reffreq,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,n_int_on,n_cycles,n_total,n_bchop,n_switch_on,n_loadinterval,startobs,telescopetimes,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastSScanDBS_deadtimes(band,reffreq,hr1,hr2,wb1,wb2,n_freq_point,data_time,n_int_on,n_bchop,n_switch_on,n_cycles,avnumchop,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanDBS_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,continuumDetection,n_cycles,tscan,tact);
    // Evaluate performance
    SScanDBS_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_total,groupnumber * n_freq_point,avnumchop * double(n_int_on),tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

////////////////////////////////////
// Auxiliary function to compute the noise of an ideal instrument with
// 100% observing efficiency for comparison
{int,double,double,double,double,double} procedure IdealHifi {
    /* Setup parameters */
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4; // Frequency scan redundancy
    int nlines = 1 in [1,240]; // Number of rows in the map
    int npoints = 10 in [1,720]; // Number of data dumps per row
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    int goalTime = 8; // Total integration time
    /* Sequence parameters */
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // Get parameters which are needed
    double center_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    double tsys = InterpolateTsys(band,center_lo_freq);
    double eta_mb = InterpolateCoupling(band,center_lo_freq);
    double[] gssb = InterpolateGssb(band,center_lo_freq);
    double phasetime = double(goalTime);
    double noiseratio = 0.0;
    // Compute total double sideband noise 
    double dsbnoise_lores = tsys * sqrt(1.0 / (effResolution{1} * 1000000.0 * phasetime));
    double dsbnoise_hires = tsys * sqrt(1.0 / (effResolution{0} * 1000000.0 * phasetime));
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Get single sideband noise equivalent
    double usbnoise_lores = dsbnoise_lores / gssb[0];
    double usbnoise_hires = dsbnoise_hires / gssb[0];
    double lsbnoise_lores = dsbnoise_lores / gssb[1];
    double lsbnoise_hires = dsbnoise_hires / gssb[1];
    // return total time with initial slew
    int returntime = goalTime;
    // Originally I had added 180s from telescope
    // Now make corrections for maps or spectral scans
    if(npoints * nlines > 1) {
        double factor = sqrt(double(nlines * npoints));
        usbnoise_lores = usbnoise_lores * factor;
        usbnoise_hires = usbnoise_hires * factor;
        lsbnoise_lores = lsbnoise_lores * factor;
        lsbnoise_hires = lsbnoise_hires * factor;
    }
    if(lo_freq_up > lo_freq) {
        {int,double,double[],int[][],int,bool} fqparms = MakeFreqGrid(band,lo_freq,lo_freq_up,redundancy,0.0,1);
        factor = sqrt(double(fqparms{0} / fqparms{4}));
        usbnoise_lores = usbnoise_lores * factor;
        usbnoise_hires = usbnoise_hires * factor;
        lsbnoise_lores = lsbnoise_lores * factor;
        lsbnoise_hires = lsbnoise_hires * factor;
    }
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {returntime,usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiseratio};
}

// Switch HIFI off, block
// Prime and Redundancy are both called, regardless of which is effectively used
//
block HIFI_global_switch_off_block_fm HIFI 3921 {
}{
    Start_block();
    //Sequentially notify PDU off then switch off S/S
    //This maybe non-instictive order is due to an ICU bug that
    //screws things up when the ICU tries to get HK from a switched off S/S
    //
    //LOU
    Hifi_HIFI_notify_PDU_status("ON","OFF","ON","ON","ON","ON");
    //HifiIltEgse_PDU_switch_off($BBID,"LO_Prime");	
    //HifiIltEgse_PDU_switch_off($BBID,"LO_Red");	
    //WBS-H
    Hifi_HIFI_notify_PDU_status("ON","OFF","ON","OFF","ON","ON");
    //HifiIltEgse_PDU_switch_off($BBID,"WBS_H");
    //WBS-V
    Hifi_HIFI_notify_PDU_status("ON","OFF","OFF","OFF","ON","ON");
    //HifiIltEgse_PDU_switch_off($BBID,"WBS_V");
    //HRS-H
    Hifi_HIFI_notify_PDU_status("ON","OFF","OFF","OFF","ON","OFF");
    //HifiIltEgse_PDU_switch_off($BBID,"HRS_H");
    //HRS-V
    Hifi_HIFI_notify_PDU_status("ON","OFF","ON","OFF","OFF","OFF");
    //HifiIltEgse_PDU_switch_off($BBID,"HRS_V");
    //ICU
    Hifi_HIFI_notify_PDU_status("OFF","OFF","OFF","OFF","OFF","OFF");
    //HifiIltEgse_PDU_switch_off($BBID,"ICU_Prime");
    //HifiIltEgse_PDU_switch_off($BBID,"ICU_Red");
    //At that stage, the instrument is idle...
}

//Procedure to get from standby to primary mode
//Concerns LO and WBS settings
procedure HifiIntoPrimary {
}{
    //Switch LO to nominal
    Set_LO_Nominal_block_aot();
    //Set applicable LO FDIR limits (SCR-2226)
    Set_LO_FDIR_temperatures_block_aot();
}

//Reduced version: IVC
//HIFI-COP-7.2-FPU_FT
procedure FPU_FT_IVC_COP_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b","8"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //General parameters in use
    string hbb_heater = "ON";
    //hot source on/off
    string chopper_loop = "CLOSE";
    //
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    double[] cresult_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = cresult_d[0];
    //applies to cold LO
    Init_MSA_ops(band,chopper_loop,lo_freq,result[0]{0},hbb_heater,prime_or_redundant);
    //
    //IVC
    IVcurve_raw_fm(band);
    //
}

//Readback of LCU Memory Patch, block
procedure LCU_readback_TPF_maker {
    string section = "P" in ["P","R"];
}{
    //
    //{int, int[]} [] runs = LcuGetMemoryRuns_ops( section);
    {int,int[]}[] runs = LcuGetMemoryRuns(section,1);
    int runcount = length(runs);
    if(runcount != 0) {
        for(int i = 0 .. runcount - 1) {
            int count = length(runs[i]{1});
            Hifi_HIFI_WBS_Zero(runs[i]{0});
            Hifi_HIFI_WBS_Zero(count);
        }
        //Complement the number of TCs sent to reach the fixed TC pattern needed for TPF
        int nb_TC_needed = 50;
        int remaining_TC = nb_TC_needed - runcount;
        mois_comment("The following " + remaining_TC + " TCs are dummy repetition of the first memory dump command");
        //
        for(int ii = 1 .. remaining_TC) {
            Hifi_HIFI_WBS_Zero(runs[0]{0});
            Hifi_HIFI_WBS_Zero(length(runs[0]{1}));
        }
    }
}

//Load and boot new OBSW from rescue, block
block Load_boot_block_ops HIFI 7929 {
}{
    //  
    mois_step("Construct the OBSW copy");
    mois_spacon("Use the OBSM or OBS-loader to prepare the load_mem TC list to build the new version of the OBSW that is to be loaded and started");
    //
    mois_step("Upload the OBSW copy to DM");
    mois_spacon("Use the OBSM or OBS-loader to run the TC list previously prepared to load the new version of the OBSW");
    //
    mois_step("Run the load boot TC");
    Hifi_HIFI_load_boot();
    delay(1);
    //The new OBSW should be booted
    mois_tmcheck("Check that the new OBSW release numbers have been updated (HI_SW_Version, HI_SW_Revision and HI_SW_Patch)");
    //
    mois_comment("Assign obsid number to procedure execution");
    mois_spacon("In the following command, the second parameter (OBS_ID) shall be replaced by a Formal Parameter value according to the list provided by the instrument ICC.");
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    //
    //Do we want to copy the new image onto the EEPROM ?
    //TC for this: Hifi_HIFI_eeprom_write -> decided to rather prepare a dedicated procedure for this.
}

// upload of memory patch table, block
//Prime/Redundant is handled with the CUS table
block LcuMemoryPatchUpload_fm HIFI 3902 {
}{
    Start_block();
    string section = GetLcuSection();
    {int,int[]}[] runs = LcuGetMemoryRuns(section,100);
    int runcount = length(runs);
    for(int i = 0 .. runcount - 1) {
        {int}[] par = [];
        int[] values = runs[i]{1};
        int count = length(values);
        for(int j = 0 .. count - 1) {
            par[j] = {values[j]};
        }
        int crc = checksum("short",values);
        Hifi_HIFI_load_LCU(runs[i]{0},count,par,crc);
        delay(2);
    }
}

// Very Short Performance Test, procedure
// Assumes LO is stabilized, in nominal mode, and instrument is ready to be configured
// Also assumes backends are ready
// This is to be used in cold context
procedure HIFI_VSPT_proc {
    string band = "1a"; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string mixer_polarization = "H" in ["H","V","B"]; //Polarization: H, V or Both
    string backend_code = "WBS" in ["WBS","HRS"]; //The backend to be used for magnet tuning
    string chop_loop = "CLOSE"; //The chopper loop status
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string mixer_for_tuning = "H" in ["H","V","B"]; //Polarization: H, V or both
}{
    //
    //Configure FPU
    //The chopper will look at rest position per default
    //
    if(mixer_polarization == "H") {
        if(mixer_for_tuning == "V") {
            error("V mixer cannot be used for tuning since only mixer H was selected.");
        }
        if(band == "0") {
            Band0_hbb_on_fm(band,chop_loop);
        } else {
            Init_MSA_H_fm(band,chop_loop,lo_freq);
        }
    }
    if(mixer_polarization == "V") {
        if(mixer_for_tuning == "H" || mixer_for_tuning == "B") {
            error("H mixer cannot be used for tuning since only mixer V was selected.");
        }
        if(band == "0") {
            Band0_hbb_on_fm(band,chop_loop);
        } else {
            Init_MSA_V_fm(band,chop_loop,lo_freq);
        }
    }
    if(mixer_polarization == "B") {
        if(band == "0") {
            Band0_hbb_on_fm(band,chop_loop);
        } else {
            Init_MSA_fm(band,chop_loop,lo_freq,"ON");
        }
    }
    //
    //Set-up LO at new frequency and performs tuning at that frequency. 
    //Assumes the band was already switched on prior to the VSPT. 
    //Also assumes we are in nominal mode.
    LO_tuning_w_mixerchoice_block_fm(band,lo_freq,mixer_for_tuning);
    //
    //Magnet tuning: only up to band 5 since band6-7 have no magnets
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        {double,string}[] result_d = ConfigurationReader("name_configwbs",["tune_target_magnet"],band,lo_freq);
        int tune_target_magnet = iround(result_d[0]{0});
        Magnet_tuning_block_fm(band,lo_freq,backend_code,tune_target_magnet);
    }
    //
    //Spectrometer attenuator tuning: should be done on Hot source
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers after tuning
    int[] res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    //HotCold measurement
    Hot_cold(band,hrs_mode,backend,res[0] * res[1],"tp",0,0);
    //
}

//Procedure to translate old band name into new convention
string procedure Translate_band_name {
    string band = "1a"; //"OLD" band naming
}{
    //Translate band name
    string band_new = "1a";
    if(band == "1a") {
        //Band 1a
        band_new = "1a";
    }
    if(band == "1b") {
        //Band 1b
        band_new = "1b";
    }
    if(band == "2a") {
        //Band 2a
        band_new = "2a";
    }
    if(band == "2b") {
        //Band 2b
        band_new = "2b";
    }
    if(band == "3a") {
        //Band 3a
        band_new = "3a";
    }
    if(band == "3b") {
        //Band 3b
        band_new = "3b";
    }
    if(band == "4a") {
        //Band 4a
        band_new = "4a";
    }
    if(band == "4b") {
        //Band 4b
        band_new = "4b";
    }
    if(band == "5a") {
        //Band 5a
        band_new = "5a";
    }
    if(band == "5b") {
        //Band 5b
        band_new = "5b";
    }
    if(band == "6a") {
        //Band 6a
        band_new = "6a";
    }
    if(band == "6b") {
        //Band 6b
        band_new = "6b";
    }
    if(band == "7a") {
        //Band 7a
        band_new = "7a";
    }
    if(band == "7b") {
        //Band 7b
        band_new = "7b";
    }

    return band_new;
}

// Generic A_M function for LSU setting
// DT - 18 Aug 2006
int[] procedure ComputeLSU_A_M_R {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; //LO frequency
}{
    //Read parameters
    double[] result = CalibrationReader("name_lsu_convertion",["multiplier","f_offset","n10","n20"],band,lo_freq);
    double multiplier = result[0];
    double f_offset = result[1];
    int n10 = iround(result[2]);
    int n20 = iround(result[3]);
    //
    //Compute LSU frequency IN MHZ
    double f_lsu = lo_freq * 1000.0 / multiplier;
    //Compute total frequency
    double f_total = f_lsu + f_offset;
    //Compute parameter n
    int n = ifloor(15.0 * (f_total / 1.875 - double(ifloor(f_total / 1.875))));
    //Compute main and offset loop parameters
    int n1 = n10 + n;
    // offset loop
    int d1 = 15;
    //offset loop
    int n2 = iround(abs(double(n20 - ifloor(f_total / 1.875) + n)));
    //main loop
    int d2 = 16;
    //
    //Compute A,M and R parameters for main and offset loop
    int m1 = ifloor(double(n1) / 10.0) - 1;
    // offset loop	
    int a1 = n1 - 10 * ifloor(double(n1) / 10.0);
    // offset loop
    int r1 = d1 - 1;
    // offset loop
    int m2 = ifloor(double(n2) / 10.0) - 1;
    // main loop	
    int a2 = n2 - 10 * ifloor(double(n2) / 10.0);
    // main loop
    int r2 = d2 - 1;
    // main loop
    //
    int[] lsu_a_m_r_parameter = [0,0,0,0,0,0];
    lsu_a_m_r_parameter[0] = m1;
    lsu_a_m_r_parameter[1] = a1;
    lsu_a_m_r_parameter[2] = r1;
    lsu_a_m_r_parameter[3] = m2;
    lsu_a_m_r_parameter[4] = a2;
    lsu_a_m_r_parameter[5] = r2;
    //
    //Conversion into main and offset LSU word
    int main_word = iround(pow(2.0,18.0) * double(ifloor(double(r2) % pow(2.0,6.0) / pow(2.0,4.0))) + pow(2.0,15.0) * double(ifloor(double(m2) % pow(2.0,9.0) / pow(2.0,7.0))) + pow(2.0,8.0) * (double(m2) % pow(2.0,9.0)) + pow(2.0,4.0) * (double(r2) % pow(2.0,6.0) % pow(2.0,4.0)) + double(a2) % pow(2.0,4.0));
    int offset_word = iround(pow(2.0,18.0) * double(ifloor(double(r1) % pow(2.0,6.0) / pow(2.0,4.0))) + pow(2.0,15.0) * double(ifloor(double(m1) % pow(2.0,9.0) / pow(2.0,7.0))) + pow(2.0,8.0) * (double(m1) % pow(2.0,9.0)) + pow(2.0,4.0) * (double(r1) % pow(2.0,6.0) % pow(2.0,4.0)) + double(a1) % pow(2.0,4.0));
    //
    //debug_print("LSU conversion result " + lsu_a_m_r_parameter);
    //debug_print("main: " + main_word + ", offset: " + offset_word);
    //
    //Compute real LO frequency set by A,M,R combination
    double nn1 = double(10 * (m1 + 1) + a1);
    double dd1 = double(r1 + 1);
    double nn2 = double(10 * (m2 + 1) + a2);
    double dd2 = double(r2 + 1);
    double flsu_back = 24000.0 + 30.0 * (nn1 / dd1 + nn2 / dd2);
    if(band == "2a" || band == "3b") {
        flsu_back = 24000.0 + 30.0 * (nn1 / dd1 - nn2 / dd2);
    }
    double flo_back = flsu_back * multiplier;
    //debug_print("Real tuned frequency: " + flo_back);
    //
    int[] resu = [0,0];
    resu[0] = main_word;
    resu[1] = offset_word;
    //Modification following SPR-1302
    resu = [resu[0] + 0xf2200000,resu[1] + 0xf2300000];
    //

    return resu;
}

// Noise ratio from an OTF line for the special case of a
// multiple scan of the same line
// 
double procedure OtfRepeatedNoiseRatio {
    double num_scans = 2.0; // number of scans of the same line
    double n = 10.0; // number of points in one scan
    double[] parameters = [0.02,0.4,0.05,0.667,2.5]; // Parameters: integration time, delay and turn-around relative to Allan time, ratio of t_off time to sqrt(n)*t_on, line length, drift exponent
}{
    // Assign parameters
    double x = parameters[0];
    double d = parameters[1];
    double doff = parameters[2];
    double qval = parameters[3];
    double alpha = parameters[4];
    // Make corrections for different calibration
    double qcorr = qval * sqrt(num_scans);
    {double,double} noisevalues = OtfNoiseValues(num_scans * n,[x,d,doff,qcorr,alpha]);
    double yn = noisevalues{0};
    yn = yn / num_scans;
    double yd = noisevalues{1};
    // Compute ratio
    double y = yd / yn;

    return y;
}

// thermal tests, fast: this is the quick health check
// Follows description of FPSS-01204
block Thermal_fast_fm HIFI 3281 {
    string band = "1a"; // HIFI band
    double lo_freq = 522.0; //LO frequency
}{
    //Start_block();
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    //
    //Get Targetted values for magnet, mixer bias, heater time and diplexer
    double[] cresult_d = CalibrationReader("name_configthermal",["dipl_h","magn_h","mbias_h","heat_h","dipl_v","magn_v","mbias_v","heat_v"],band,0.0);
    double target_dipl_h = cresult_d[0];
    double target_magn_h = cresult_d[1];
    double target_mbias_h = cresult_d[2];
    double target_heat_h = cresult_d[3];
    double target_dipl_v = cresult_d[4];
    double target_magn_v = cresult_d[5];
    double target_mbias_v = cresult_d[6];
    double target_heat_v = cresult_d[7];
    //
    //Read SIF
    cresult_d = CalibrationReader("name_configthermal",["sif1hv","sif1hc","sif2hv","sif2hc","sif3hv","sif3hc"],band,0.0);
    double volt_H_SIF_1 = cresult_d[0];
    double curr_H_SIF_1 = cresult_d[1];
    double volt_H_SIF_2 = cresult_d[2];
    double curr_H_SIF_2 = cresult_d[3];
    double volt_H_SIF_3 = cresult_d[4];
    double curr_H_SIF_3 = cresult_d[5];
    // 
    cresult_d = CalibrationReader("name_configthermal",["sif1vv","sif1vc","sif2vv","sif2vc","sif3vv","sif3vc"],band,0.0);
    double volt_V_SIF_1 = cresult_d[0];
    double curr_V_SIF_1 = cresult_d[1];
    double volt_V_SIF_2 = cresult_d[2];
    double curr_V_SIF_2 = cresult_d[3];
    double volt_V_SIF_3 = cresult_d[4];
    double curr_V_SIF_3 = cresult_d[5];
    //
    //Read FIF: these are the nominal values
    cresult_d = CalibrationReader("name_configthermal",["fif1v","fif1c","fif2v","fif2c"],band,0.0);
    double volt_H_FIF_1 = cresult_d[0];
    double curr_H_FIF_1 = cresult_d[1];
    double volt_H_FIF_2 = cresult_d[2];
    double curr_H_FIF_2 = cresult_d[3];
    //
    double volt_V_FIF_1 = cresult_d[0];
    double curr_V_FIF_1 = cresult_d[1];
    double volt_V_FIF_2 = cresult_d[2];
    double curr_V_FIF_2 = cresult_d[3];
    //
    //Get chopper settings
    string chop_sine_s = "ON";
    string chop_loop = "CLOSE";
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2"],band,lo_freq);
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //  
    result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,lo_freq);
    double calibcurrent = result_d[0]{0};
    double bias_H = target_mbias_h;
    double magnetcurrent_H = target_magn_h;
    double diplex_H = target_dipl_h;
    double bias_V = target_mbias_v;
    double magnetcurrent_V = target_magn_v;
    double diplex_V = target_dipl_v;
    result_d = ConfigurationReader("name_confilfpu",["chop_cold"],band,lo_freq);
    double chopper = result_d[0]{0};
    chopper = Check_Chopper_Prime_Redundant(chopper);
    //
    //Get diplexer codes
    if(band_nb <= 2 || band_nb == 5) {
        int diplex_h_ctrl_mode = 0;
        int diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
    }
    //
    //1. Switch on diplexer, SIF, FIF, magnets and mixer bias
    //
    //Send command to FPU and wait 25 min.
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(1500);
    //
    //2. Check heater current effect on temperature: Let current ON
    //    during the standard deflux time.
    //We will bias the junction at low bias to check when 
    //the heater effect is effective
    result_d = ConfigurationReader("name_confilfpu",["bias_very_low_h","bias_very_low_v"],band,lo_freq);
    bias_H = result_d[0]{0};
    bias_V = result_d[1]{0};
    Mixerbias(bias_H,bias_V);
    //
    //Magnets need to be switched to 0 prior to the deflux
    Hifi_HIFI_CH1_MX_MG_C($BBID,0.0);
    Hifi_HIFI_CV1_MX_MG_C($BBID,0.0);
    delay(1);
    //
    //Get time during which one wants to send the pulse
    double max_heater_time_h = target_heat_h * 1000.0;
    //in msec
    double max_heater_time_v = target_heat_v * 1000.0;
    //in msec
    //Start to send the pulse
    //H-polar first
    Hifi_HIFI_HF_CH1_DHTR_C($BBID,max_heater_time_h);
    delay(iceil(max_heater_time_h / 1000.0) + 1);
    //V-polar then
    Hifi_HIFI_HF_CV1_DHTR_C($BBID,max_heater_time_v);
    delay(iceil(max_heater_time_v / 1000.0) + 1);
    //
    //3. Heater back to 0: achieved automatically after the above is elapsed.
    //Extra delay to cool down in band 0 before switch to next band
    Band0_chopper_on_proc_fm("0","CLOSE");
    //Wait another 25 minutes
    delay(1500);
    //
}

//Readback of LCU Memory Patch, block
block LcuMemoryPatchReadback_fm HIFI 3903 {
}{
    Start_block();
    string section = GetLcuSection();
    {int,int[]}[] runs = LcuGetMemoryRuns(section,498);
    int runcount = length(runs);
    for(int i = 0 .. runcount - 1) {
        int count = length(runs[i]{1});
        Hifi_HIFI_dump_memory("LCU",runs[i]{0},count);
        //	delay( iceil( double( count ) *.003 ) ); // 3 msec per word readout
        //	Workaround
        delay(2 + iceil(double(count) * 0.0030));
        // 3 msec per word readout
    }
}

// Initialisation of FPU, block with only V-MSA in use
// It is only for cold context !
block Init_MSA_V_fm HIFI 3208 {
    string band = "1a";
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
}{
    Start_block();
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],"0",0.0);
    //
    double volt_H_FIF_1 = result_d[0]{0};
    double curr_H_FIF_1 = result_d[1]{0};
    double volt_H_FIF_2 = result_d[2]{0};
    double curr_H_FIF_2 = result_d[3]{0};
    //
    double volt_H_SIF_1 = result_d[4]{0};
    double curr_H_SIF_1 = result_d[5]{0};
    double volt_H_SIF_2 = result_d[6]{0};
    double curr_H_SIF_2 = result_d[7]{0};
    double volt_H_SIF_3 = result_d[8]{0};
    double curr_H_SIF_3 = result_d[9]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current_on"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,0.0);
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //In case of band 6 or 7, bias have been set to 4mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    //Magnet are so far at maximum value. Now set to nominal
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
        Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
        delay(1);
    }
    //
    Hifi_HIFI_non_periodic_hk_FCU();
}

//Shutter rotation during peakup in ILT context, procedure
//Shutter is used to partially blind external BB load
procedure Peakup_shutter_rotation_proc_fm {
    string band = "1" in ["1","2","3","4","5","6","7"]; // HIFI band
    int position = 1 in [1,9]; //peakup pattern sequence number: from 1 to 9
    string peakup_matrix = "centred" in ["centred","offseted","flat"]; //Which brightness distribution to simulate with shutter
}{
    //Get number of shutter rotation steps depending on position number
    string band_nb = band + "a";
    string name_shutter_pos = "name_shutter_pos_centred";
    if(peakup_matrix == "offseted") {
        name_shutter_pos = "name_shutter_pos_offseted";
    }
    {double,string}[] result = ConfigurationReader(name_shutter_pos,["shutter_step"],band_nb,double(position));
    //If flat distribution is chosen, the shutter should not be moved
    int shutter_step = iround(result[0]{0});
    if(peakup_matrix == "flat") {
        shutter_step = 1;
    }
    //
    //Rotate shutter: number of steps is accounted from open position
    //HifiIltEgse_FPU_set_shutter_betw($BBID,shutter_step);
    //Fixed delay
    result = ConfigurationReader(name_shutter_pos,["shutter_delay"],band_nb,double(position));
    delay(iround(result[0]{0}));
    //
}

///////////////////////////////////////////////////////////////////////////////
// Subroutine for HRS settings shared between ConfigSpectroscopy and DataTaking
{int,int,int,int} procedure HrsSubbandSelection {
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands}, WBS1/2 {used, channel windows}
}{
    // Seection of HRS subbands in correct order
    int[] widebits = [129,66,36,24];
    // [10000001,01000010,00100100,00011000]
    int[] lowbits = [192,48,12,3];
    // [11000000,00110000,00001100,00000011]
    int[] normalbits = [240,15];
    // [11110000,00001111]
    int[] highbits = [255];
    // [11111111]
    // HRS-H
    int hrsh_sel = 0;
    int n_hchannels = 0;
    if(backendreadoutparms{0}{0} == true) {
        // normal resolution
        int maxbands = 2;
        int[] bits = normalbits;
        int n_perband = 2064;
        if(backendreadoutparms{0}{1} > 2) {
            // wide resolution
            maxbands = 4;
            bits = widebits;
            n_perband = 1032;
        } else {
            if(backendreadoutparms{0}{1} > 1) {
                // low resolution
                maxbands = 4;
                bits = lowbits;
                n_perband = 1032;
            } else {
                if(backendreadoutparms{0}{1} < 1) {
                    // high resolution
                    maxbands = 1;
                    bits = highbits;
                    n_perband = 4128;
                }
            }
        }
        for(int i0 = 0 .. maxbands - 1) {
            if(backendreadoutparms{0}{2}[i0]) {
                hrsh_sel = hrsh_sel + bits[i0];
                n_hchannels = n_hchannels + n_perband;
            }
        }
    }
    // HRS-V
    int hrsv_sel = 0;
    int n_vchannels = 0;
    if(backendreadoutparms{1}{0} == true) {
        // normal resolution
        maxbands = 2;
        bits = normalbits;
        n_perband = 2064;
        if(backendreadoutparms{1}{1} > 2) {
            // wide resolution
            maxbands = 4;
            bits = widebits;
            n_perband = 1032;
        } else {
            if(backendreadoutparms{1}{1} > 1) {
                // low resolution
                maxbands = 4;
                bits = lowbits;
                n_perband = 1032;
            } else {
                if(backendreadoutparms{1}{1} < 1) {
                    // high resolution
                    maxbands = 1;
                    bits = highbits;
                    n_perband = 4128;
                }
            }
        }
        for(int i1 = 0 .. maxbands - 1) {
            if(backendreadoutparms{1}{2}[i1]) {
                hrsv_sel = hrsv_sel + bits[i1];
                n_vchannels = n_vchannels + n_perband;
            }
        }
    }

    return {hrsh_sel,hrsv_sel,n_hchannels,n_vchannels};
}

{int,double,double,double,double,double} obs HifiPointModeDBS {
    string modeName = "dbs";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Single Point - DBS slowChop",{data_time,0,0,n_switch_on,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,bool,int,int,int} pre_timing = DBS_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},bool,double,double} post_timing = DBS_post_timing(pre_timing,telescopetimes,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",post_timing{1},n_cycles);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_seq = post_timing{1}{8};
    int n_loadinterval = post_timing{1}{7};
    bool end_load = post_timing{1}{9};
    int shiftlength = post_timing{1}{10};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        DBS_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,n_loadinterval,end_load,final_load,startobs,telescopetimes,loadlength,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = DBS_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBS_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,n_seq * (n_load + 1),tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Stability test, procedure, case 4
// Measurement of internal cold against external cold
procedure Proc_stability_intcold_extcold {
    string band = "1a"; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total (co-added) integration time of a phase in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "slowchop" in ["slowchop","fastchop"]; //Whether to use slowchop or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    //
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //Look at HBB
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        //Configure and tune backends
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration after tuning: done later
    //Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    Stability_intcold_extcold_fm(band,n,integ_time,hrs_mode,backend,chopmode,chop_phase);
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
    //2 sec. integration
}

//////////////////////////////////////////////////////////////////////////
// Auxiliary procedure to compute sum of dead times across the map
{int,int,int} procedure GetAllCrossSlewTimes {
    int[] telescopetimes = [300,180,20,0,21,0,2,10];
    int scansize = 1; // Number of points measured in one scan
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF pointing cycles
}{
    // Use telescope return parameters
    int numpoints = telescopetimes[6];
    if(scansize > 1) {
        // Scan return field
        int n_scans = numpoints / (2 * scansize * n_cycles);
        int sumslews = 0;
        int sumnods = 0;
        int sumreturns = 0;
        for(int i1 = 0 .. numpoints - 2) {
            int theslew = telescopetimes[i1 + 7];
            if(i1 % scansize == 0) {
                if(i1 % (2 * scansize) == 0) {
                    // within A-A or B-B
                    sumreturns = sumreturns + theslew;
                } else {
                    // Nod instead of slew
                    sumnods = sumnods + theslew;
                }
            } else {
                sumslews = sumslews + theslew;
            }
        }
        // Parameters irrelevant for scansize>1
        int shortmove = 0;
        // Main returns
        int tinscandead = sumnods + sumslews;
        int toutscandead = sumreturns;
    } else {
        // trivial computation for scansize=1;
        // Single point per nod
        int nodtime = telescopetimes[2];
        // Slew time to second nod
        int returntime = telescopetimes[3];
        // Idle time between two phases
        // Scan return field
        numpoints = telescopetimes[6];
        n_scans = numpoints / scansize;
        sumreturns = n_scans * (n_cycles - 1) * returntime;
        // Initial values
        sumslews = 0;
        shortmove = returntime;
        // All return values
        for(int i2 = 0 .. numpoints - 2) {
            theslew = telescopetimes[i2 + 7];
            sumslews = sumslews + theslew;
            shortmove = imin(shortmove,theslew);
        }
        tinscandead = n_scans * n_cycles * nodtime;
        toutscandead = sumslews + sumreturns;
    }

    return {tinscandead,toutscandead,shortmove};
}

//  LCU1b configuration and tuning, procedure
procedure LCU1b_config_tune_proc_fm {
    string band = "1b"; // HIFI band
    double lo_freq = 600.0 in [566.0,633.0]; //LO frequency
    double drain_2_factor = 100.0; //Percentage factor of the targetted drain voltage
}{
    error("This module is obsolete: use LO_tuning_block_fm  instead");
}

//HIFI-COP-7.2-FT: Regular FT during PV and routine for health monitoring
obs HifiEng_HealthMon_FT {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(HealthMon_FT_COP_proc_ops(prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            HealthMon_FT_COP_proc_ops(prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// WBS configuration with laser choice, block
// Both polarizations are treated
block WBS_config_w_laser_and_att_block_fm HIFI 3636 {
    string band = "1a"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
    int[] att_h = [7,7,7,7,15]; //User input att. for optimum level H-polar
    int[] att_v = [7,7,7,7,15]; //User input att. for optimum level V-polar
}{
    //Start_block();
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4","hwh_att_band3","hwh_att_band2","hwh_att_band1","hwh_att_in"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = att_h[3];
    int hwh_att_band3 = att_h[2];
    int hwh_att_band2 = att_h[1];
    int hwh_att_band1 = att_h[0];
    int hwh_att_in = att_h[4];
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4","hwv_att_band3","hwv_att_band2","hwv_att_band1","hwv_att_in"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = att_v[3];
    int hwv_att_band3 = att_v[2];
    int hwv_att_band2 = att_v[1];
    int hwv_att_band1 = att_v[0];
    int hwv_att_in = att_v[4];
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// These scripts allow to perform the FPU Functional
// tests at SS level. They correspond to the procedures
// prepared by PD.
//
// DT - 28 Sep 2004: First draft for QM
//	20 Jul 2005: Update for FM
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Modes: see fm_testmodes.cus
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Associated blocks
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// First part of FPSS FM functional test without spectra, block
// Check that IF amplification is effective (only HK)
procedure FT_FPU_check_IF_nospectra_fm {
    string band = "1a";
    string context = "warm" in ["warm","cold"]; //Test context: warm or cold
}{
    //At that stage, all IFs are ON
    //
    //Switch OFF FIF
    //Get parameters
    {double,string}[] result_h = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    if(context == "warm") {
        result_h = ConfigurationReaderWarm("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    }
    //
    int band_nb = iround(result_h[0]{0});
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = 0.075;
    double curr_H_FIF_1 = 0.5;
    double volt_H_FIF_2 = 0.075;
    double curr_H_FIF_2 = 0.5;
    //
    double volt_H_SIF_1 = result_h[5]{0};
    double curr_H_SIF_1 = result_h[6]{0};
    double volt_H_SIF_2 = result_h[7]{0};
    double curr_H_SIF_2 = result_h[8]{0};
    double volt_H_SIF_3 = result_h[9]{0};
    double curr_H_SIF_3 = result_h[10]{0};
    // 
    {double,string}[] result_v = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    if(context == "warm") {
        result_v = ConfigurationReaderWarm("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    }
    //
    //
    double volt_V_FIF_1 = 0.075;
    double curr_V_FIF_1 = 0.5;
    double volt_V_FIF_2 = 0.075;
    double curr_V_FIF_2 = 0.5;
    //
    double volt_V_SIF_1 = result_v[4]{0};
    double curr_V_SIF_1 = result_v[5]{0};
    double volt_V_SIF_2 = result_v[6]{0};
    double curr_V_SIF_2 = result_v[7]{0};
    double volt_V_SIF_3 = result_v[8]{0};
    double curr_V_SIF_3 = result_v[9]{0};
    //
    string chop_sine_s = "ON";
    string chop_loop = "CLOSE";
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,0.0);
    if(context == "warm") {
        result = ConfigurationReaderWarm("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,0.0);
    }
    //
    int chop_G1 = iround(result[0]{0});
    int chop_G2 = iround(result[1]{0});
    int chop_Z1 = iround(result[2]{0});
    int chop_Z2 = iround(result[3]{0});
    int chop_P2 = iround(result[4]{0});
    //
    //
    //  
    double calibcurrent = result[7]{0};
    //
    double bias_H = 0.0;
    double magnetcurrent_H = 0.0;
    double diplex_H = 0.0;
    double bias_V = 0.0;
    double magnetcurrent_V = 0.0;
    double diplex_V = 0.0;
    double chopper = 0.0;
    //
    //
    chopper = Check_Chopper_Prime_Redundant(chopper);
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result[0]{0});
    delay(config_fpu_delay);
    //
    //Switch OFF SIF
    //
    volt_H_SIF_1 = 0.075;
    curr_H_SIF_1 = 0.5;
    volt_H_SIF_2 = 0.075;
    curr_H_SIF_2 = 0.5;
    volt_H_SIF_3 = 0.075;
    curr_H_SIF_3 = 0.5;
    // 
    volt_V_SIF_1 = 0.075;
    curr_V_SIF_1 = 0.5;
    volt_V_SIF_2 = 0.075;
    curr_V_SIF_2 = 0.5;
    volt_V_SIF_3 = 0.075;
    curr_V_SIF_3 = 0.5;
    //
    chopper = Check_Chopper_Prime_Redundant(chopper);
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    delay(config_fpu_delay);
    //
}

// Needs the chopper in open-loop mode !!
block Chopper_openloop_scan_block_ops HIFI 7694 {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red 
}{
    //Hard-coded RAW values for end stops and rest position 
    int low = 1298;
    //This is slightly further the low end-stop
    int high = 2548;
    //This is slightly further the high end-stop
    int zero = 2048;
    //This is the zero position
    int step = 50;
    //
    //Go-nogo criteria - taken from FPSS-01046 issue 3
    double c0 = -7.71;
    double c0_E = 0.2;
    double c1 = 8.73;
    double c1_E = 0.2;
    if(prime_or_redundant == "Red") {
        c0 = -8.76;
        c0_E = 0.2;
        c1 = 7.61;
        c1_E = 0.2;
    }
    //
    int chopper_pos = zero;
    //Scan from zero to end-stop high
    mois_comment("Scanning from 2048 RAW to 2548 RAW");
    while(chopper_pos <= high) {
        //Prime/Red has no effect on RAW to send, only to the TC name
        if(prime_or_redundant == "Prime") {
            Hifi_HIFI_P_Chopper_Rot_RAW($BBID,chopper_pos);
            //Rotate chopper
        } else {
            Hifi_HIFI_R_Chopper_Rot_RAW($BBID,chopper_pos);
            //Rotate chopper
        }
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent value
        mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to " + chopper_pos + " in RAW units");
        chopper_pos = chopper_pos + step;
        delay(2);
    }
    //Go-nogo criterion after first scan
    mois_tmcheck("Check that parameter HF_APR_CH_ROT is within " + c0 + " +/- " + c0_E + " V. If not procedure needs to be aborted and the HIFI ICC contacted.");
    //Scan from end-stop high to end-stop low
    mois_comment("Scanning from 2548 RAW to 1298 RAW");
    chopper_pos = 2498;
    while(chopper_pos >= low) {
        //Prime/Red has no effect on RAW to send, only to the TC name
        if(prime_or_redundant == "Prime") {
            Hifi_HIFI_P_Chopper_Rot_RAW($BBID,chopper_pos);
            //Rotate chopper
        } else {
            Hifi_HIFI_R_Chopper_Rot_RAW($BBID,chopper_pos);
            //Rotate chopper
        }
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent value
        mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to " + chopper_pos + " in RAW units");
        chopper_pos = chopper_pos - step;
        delay(2);
    }
    //Go-nogo criterion after second scan
    mois_tmcheck("Check that parameter HF_APR_CH_ROT is within " + c1 + " +/- " + c1_E + " V. If not procedure needs to be aborted and the HIFI ICC contacted.");
    //Scan from end-stop low to zero
    mois_comment("Scanning from 1298 RAW to 2048 RAW");
    chopper_pos = 1348;
    while(chopper_pos <= zero) {
        //Prime/Red has no effect on RAW to send, only to the TC name
        if(prime_or_redundant == "Prime") {
            Hifi_HIFI_P_Chopper_Rot_RAW($BBID,chopper_pos);
            //Rotate chopper
        } else {
            Hifi_HIFI_R_Chopper_Rot_RAW($BBID,chopper_pos);
            //Rotate chopper
        }
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent value
        mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to " + chopper_pos + " in RAW units");
        chopper_pos = chopper_pos + step;
        delay(2);
    }
}

/////////////////////////////////////////////////////////////
// FPU configuration, procedure: is not used at the present time..
procedure Configure_FPU_proc_fm {
    string band = "1a"; // HIFI band
    double lo_freq = 522.0; //LO frequency
    string mixer_polarization = "B" in ["H","V","B"]; //Polarization: H, V, or both (B)
    string chop_loop = "CLOSE"; //Chopper loop status
    double chop = 0.0; //Chopper position
}{
    //Fetch parameters
    //H-polar
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    //V-polar
    result_d = ConfigurationReader("name_confilfpu",["band","fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[1]{0};
    double curr_V_FIF_1 = result_d[2]{0};
    double volt_V_FIF_2 = result_d[3]{0};
    double curr_V_FIF_2 = result_d[4]{0};
    //
    double volt_V_SIF_1 = result_d[5]{0};
    double curr_V_SIF_1 = result_d[6]{0};
    double volt_V_SIF_2 = result_d[7]{0};
    double curr_V_SIF_2 = result_d[8]{0};
    double volt_V_SIF_3 = result_d[9]{0};
    double curr_V_SIF_3 = result_d[10]{0};
    //Set IF according to polarization in use
    if(mixer_polarization == "H") {
        //Set V-polar to 0
        volt_V_FIF_1 = 0.0;
        curr_V_FIF_1 = 0.0;
        volt_V_FIF_2 = 0.0;
        curr_V_FIF_2 = 0.0;
        //
        volt_V_SIF_1 = 0.0;
        curr_V_SIF_1 = 0.0;
        volt_V_SIF_2 = 0.0;
        curr_V_SIF_2 = 0.0;
        volt_V_SIF_3 = 0.0;
        curr_V_SIF_3 = 0.0;
        //
    }
    if(mixer_polarization == "V") {
        //Set H-polar to 0
        volt_H_FIF_1 = 0.0;
        curr_H_FIF_1 = 0.0;
        volt_H_FIF_2 = 0.0;
        curr_H_FIF_2 = 0.0;
        //
        volt_H_SIF_1 = 0.0;
        curr_H_SIF_1 = 0.0;
        volt_H_SIF_2 = 0.0;
        curr_H_SIF_2 = 0.0;
        volt_H_SIF_3 = 0.0;
        curr_H_SIF_3 = 0.0;
        //
    }
    //
    //Chopper settings
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //Freq. dependent bias and magnet settings
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_magn_h","norm_bias_v","norm_magn_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double norm_magnetcurrent_H = result_d[1]{0};
    double bias_V = result_d[2]{0};
    double norm_magnetcurrent_V = result_d[3]{0};
    //Max. magnets for hysteresis
    result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
    double magnetcurrent_H = result_d[0]{0};
    double magnetcurrent_V = result_d[1]{0};
    //
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    chop = Check_Chopper_Prime_Redundant(chop);
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chop,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //In case of band 6 or 7, bias have been set to 4mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    //Magnet are so far at maximum value. Now set to nominal
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
        Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
        delay(1);
    }
    //
    Hifi_HIFI_non_periodic_hk_FCU();
    delay(1);
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CUS scripts dedicated to instrument configuration
// and setup in AOT framework
//
// Main difference with ILT CUS is that input parameters
// are here in the form provided by HSPOT.
//
// DT - 05-June-06
// VO - 10-07-2006
// DT - 18-09-2006
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
/////////////////////////////
// Global procedures
//Tune HIFI at frequency of interest
procedure HIFITune {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; //LO frequency
    bool hrs1used = true; // HRS1 parameter =used
    bool hrs2used = true; // HRS2 parameter
    bool wbs1used = true; // WBS1 parameter =used
    bool wbs2used = true; // WBS2 parameter
    string target_name = "normal"; // Name of target level
}{
    //LO power tuning: could use either H or V polar
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    double x = result[0]{0};
    string tuningbackend = "H";
    if(iround(x) == 2) {
        tuningbackend = "V";
    } else {
        tuningbackend = "H";
    }
    LO_tuning_block_aot(band,lo_freq / 1000.0,lo_freq / 1000.0,tuningbackend,true,true,false);
    //Magnet tuning: could use either HRS or WBS. Not done for bands1,2,6,7 (SCR-2380)
    if(band == "3a" || band == "3b" || band == "4a" || band == "4b" || band == "5a" || band == "5b") {
        // Currently only the HRS is used
        tuningbackend = "HRS";
        Magnet_tuning_block_aot(band,lo_freq / 1000.0,tuningbackend);
    }
    //
    //Spectrometer attenuator tuning on HBB
    if(wbs1used || wbs2used) {
        WBS_attenuators_block(band,lo_freq / 1000.0,target_name,false);
    }
    if(hrs1used || hrs2used) {
        HRS_tune_block_aot(band);
    }
}

{int,double,double,double,double,double} obs HifiMappingModeLoadChopOTFNoRef {
    string modeName = "load-raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period defines number of lines between two loads
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Mapping - OTF Map Load Chop noRef",{data_time,0,0,n_switch_on,0,0,0,0,n_cycles,load_interval});
    // Auxiliary routine for API parameter correction
    {double,double,int} mapused = ValidMapSize(band,lo_freq,lineDistance,nlines,stepsize,npoints,2 * data_time * n_switch_on);
    double line_used = mapused{0};
    double scanvelocity = mapused{1};
    int npoints_used = mapused{2};
    // Call first part of the timing computer
    {int,int,int,int,bool,int,int} pre_timing = OTFLoadChopNoRef_pre_timing(nlines,npoints_used,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,int} tpar = OTFDoubleChopNoRef_telescope(naifid,onPosition,lineDistance,nlines,line_used,scanvelocity,band,lo_freq,n_cycles,pre_timing);
    // Dummy call to spacecraft command
    int[] telescopetimes = line_scan_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,bool,int,int},double,double} post_timing = OTFDoubleChopNoRef_post_timing(pre_timing,telescopetimes,nlines,data_time,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = OTFDoubleChopNoRef_telescope(naifid,onPosition,lineDistance,nlines,line_used,scanvelocity,band,lo_freq,n_cycles,post_timing{1});
    // Call telescope command
    telescopetimes = line_scan_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{0};
    bool end_load_on = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{2};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        OTFLoadChopNoRef_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,npoints_used * n_switch_on,n_loadinterval,nlines * n_cycles,end_load_on,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SingleChop_deadtimes("fs",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,npoints_used * n_switch_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = PositionSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_switch_on * n_cycles,tscan,tdead);
    // Evaluate performance
    OTFDoubleChopNoRef_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints_used,n_switch_on * n_cycles,false,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Switch HIFI on, procedure
//
procedure HIFI_global_switch_on_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Sequentially switches on, then notify PDU
    //
    //WBS-H
    mois_step("Switch ON WBS-H S/S");
    PDU_switch_on_block_ops("WBS_H");
    mois_comment("Notify PDU status for WBS-H");
    HIFI_notify_PDU_status_on_block_ops("ON","OFF","OFF","ON","OFF","OFF","WBSH");
    //WBS-V
    mois_step("Switch ON WBS-V S/S");
    PDU_switch_on_block_ops("WBS_V");
    mois_comment("Notify PDU status for WBS-H");
    HIFI_notify_PDU_status_on_block_ops("ON","OFF","ON","ON","OFF","OFF","WBSV");
    //HRS-H and HRS-V are first powered ON, FT#0 is done, then notify PDU
    mois_step("Switch ON HRS-H S/S");
    PDU_switch_on_block_ops("HRS_H");
    mois_step("Switch ON HRS-V S/S");
    PDU_switch_on_block_ops("HRS_V");
    //HRS FT#0 and special HK handling for this
    mois_step("HRS start-up");
    mois_comment("House-keeping for HRS-H and HRS-V is de-selected");
    Switch_HK_block_ops("ON","ON","ON","ON","OFF","OFF");
    mois_comment("Notify PDU status for HRS-H and HRS-V");
    HIFI_notify_PDU_status_on_block_ops("ON","OFF","ON","ON","OFF","ON","HRSH");
    HIFI_notify_PDU_status_on_block_ops("ON","OFF","ON","ON","ON","ON","HRSV");
    HRS_functional_test_No_0_block_ops();
    mois_comment("House-keeping for HRS-H and HRS-V is selected again");
    Switch_HK_block_ops("ON","ON","ON","ON","ON","ON");
    mois_comment("Initial configuration of HRS blocks and LO");
    HRS_standby_block_ops("0",["wb","wb"]);
    //LOU
    mois_step("Switch ON LO S/S");
    string lo_subsys = "LO_Prime";
    if(prime_or_redundant == "Red") {
        lo_subsys = "LO_Red";
    }
    PDU_switch_on_block_ops(lo_subsys);
    mois_comment("Notify PDU status for LCU");
    HIFI_notify_PDU_status_on_block_ops("ON","ON","ON","ON","ON","ON","LCU");
}

{int,double,double,double,double,double} obs HifiSScanModeFSwitch {
    string modeName = "fs-freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_switch_off = 1 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - Frequency Switch Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = SScanFSwitch_pre_timing(band,lo_freq,lo_freq_up,redundancy,freq_throw,effResolution,hr1,hr2,wb1,wb2,data_time,data_time_off,n_switch_on,n_switch_off,n_freq_point,n_cycles,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    int n_total = groupnumber * n_cycles;
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,reffreq,pre_timing{0},n_total);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},double,double,double} post_timing = SScanDoubleChop_post_timing(pre_timing{0},telescopetimes,n_freq_point,groupnumber,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,reffreq,post_timing{1},n_total);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    // normal pre_timing values
    int on_inttime = post_timing{1}{0};
    int off_inttime = post_timing{1}{1};
    int n_loadinterval = post_timing{1}{7};
    int n_long_on = post_timing{1}{8};
    int n_long_off = post_timing{1}{9};
    int shiftlength = post_timing{1}{5};
    int initlength = post_timing{1}{14};
    bool final_load = post_timing{1}{12};
    // efficiency parameters
    double avnumchop_on = post_timing{2};
    double avnumchop_off = post_timing{3};
    double tscan = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        SScanFSwitch_commanding(band,reffreq,freq_throw,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,data_time_off,n_switch_on,n_switch_off,n_long_on,n_long_off,n_cycles,n_total,n_loadinterval,final_load,startobs,telescopetimes,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = SScanDoubleChop_deadtimes("fs",band,reffreq,hr1,hr2,wb1,wb2,n_freq_point,data_time,data_time_off,n_switch_on,n_switch_off,n_long_on,n_long_off,n_cycles,avnumchop_on,avnumchop_off,tscan);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanFSwitch_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,on_inttime,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    SScanDoubleChop_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_freq_point,n_cycles,groupnumber * n_freq_point,avnumchop_on,avnumchop_off,true,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Reset observation ID - closes observation
block HIFICloseObs HIFI 6999 {
}{
    // Previous command my have used second bus slot - use NOOP to fill
    Hifi_HIFI_noop();
    // Switch to slow housekeeping
    {string,int,double,double,double,double} hkparms = PeriodicHKParms("slow");
    string[] pattern = QueryHKPattern(true);
    Hifi_HIFI_Housekeeping_on(hkparms{0},pattern[0],pattern[1],pattern[2],pattern[3],pattern[4],pattern[5]);
    //Fetch last obsid applicable
    {double,string}[] result = ConfigurationReader("name_lastobsid",["last_obsid_current"],"0",0.0);
    int closing_obsid = iround(result[0]{0});
    //Close OBSID
    Hifi_HIFI_Set_OBS_ID(0,closing_obsid);
    // clean bus
    delay(1);
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure SScanFSwitch_commanding {
    string band = "4a"; // HIFI band
    double reffreq = 978300.0; // Reference characteristic LO frequency 
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int grouplen = 1; // Number of frequency steps per nodding phase
    int[][] grouporder = [[0],[0]]; // Sequence to trace frequency points in both phases
    double[] freqgrid = [978053.7,978301.8,978381.1]; // Table of frequency points
    bool retuning = false; // need for WBS retuning
    double[] targetlevels = [1.0,1.0,1.0]; // WBS tuning levels
    int data_time = 4; // chunk size
    int data_time_off = 4; // data dump interval on OFF
    int n_per_on = 1; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int n_per_off = 1; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_long_on = 1; // number of cycles on ON without retuning
    int n_long_off = 1; // number of cycles on OFF without retuning
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int allsteps = 4; // Total number of frequency pointing periods
    int n_loadinterval = 1; // number of nods before a load measurement
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int shiftlength = 0; // Shift of the loop start relative to the pointing
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    // First frequency
    double runningfreq = freqgrid[grouporder[1][0]];
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] onrates = dataparms{1};
    dataparms = DataTaking(backendreadoutparms,data_time_off);
    double[] offrates = dataparms{1};
    int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,reffreq,backendreadoutparms);
    // recompute load duration for initial load measurement
    int loadlength = duration(SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,true,eff_resolution{0},data_time,backendreadoutparms));
    loadlength = loadlength + readoutdead;
    // Tuning levels
    string[] targetnames = TargetNames(band,reffreq,retuning,targetlevels);
    string target = targetnames[0];
    // All commands with a duration possibly depending on the frequency
    // are taken at the reference frequency to guarantee synchonization
    // Declare auxiliary variables to be used in the loops
    int i_freqcycles = 0;
    int i_group = 0;
    int i_phase = 0;
    // variables storing the configuration setting
    bool islong = false;
    bool isinvalid = true;
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Instrument Initialization:  The instrument tuning is done as early as
            // possible, the load calibration as late as possible
            //
            HIFIInitObs();
            TuneHIFIFsw(band,runningfreq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},target);
            delay(tinitslew - (time() - startobs) - loadlength + shiftlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,true,eff_resolution{0},data_time,backendreadoutparms);
            if(shiftlength > 0) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 7) {
            // The NOD-state represents our OFF position
            // Reset group counter
            i_group = 0;
            runintostate = false;
            // long integrations not possible in last and first PS cycle
            if(n_cycles > 1 && state[2] % n_cycles != state[2] % 2) {
                if(isinvalid || !islong) {
                    HIFIConfigureFSwitchIntegration(data_time_off,n_long_off,band,reffreq,backendreadoutparms);
                    islong = true;
                    isinvalid = false;
                }
                HIFIFSwitchOffIntegration(data_time_off,n_long_off,band,reffreq,offrates);
            } else {
                if(isinvalid || islong) {
                    HIFIConfigureFSwitchIntegration(data_time_off,n_per_off,band,reffreq,backendreadoutparms);
                    islong = false;
                    isinvalid = false;
                }
                // No group scanning on OFF
                HIFIFSwitchOffIntegration(data_time_off,n_per_off,band,reffreq,offrates);
                // Now we switch to the next frequency group or repeat the cycle
                if(state[2] % n_cycles == 0 && state[2] % 2 == 0) {
                    // Big tuning step, but not at end of observation
                    if(state[2] < allsteps) {
                        i_freqcycles = i_freqcycles + 1;
                        runningfreq = freqgrid[grouporder[1][0] + i_freqcycles * grouplen];
                        target = targetnames[i_freqcycles];
                        HIFIRetuneFsw(band,runningfreq,freq_throw,target);
                        runintostate = true;
                    } else {
                        // final load measurement if requested
                        if(final_load) {
                            delay(readoutdead);
                            SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,false,eff_resolution{0},data_time,backendreadoutparms);
                            runintostate = true;
                        }
                    }
                }
            }
            // Active WBS HK if we have a nod slew without calibration
            if(state[2] % 2 == 1) {
                isinvalid = true;
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 3) {
            // The POINT-state represents our source position
            i_phase = state[2] % 2;
            // ON integration
            runintostate = false;
            // long integrations not possible in last and first nod cycle
            if(n_cycles > 1 && state[2] % n_cycles != (state[2] % 2 + 1) % 2) {
                if(isinvalid || !islong) {
                    HIFIConfigureFSwitchIntegration(data_time,n_long_on,band,reffreq,backendreadoutparms);
                    islong = true;
                    isinvalid = false;
                }
                HIFIFSwitchOnIntegration(data_time,n_long_on,band,reffreq,onrates);
            } else {
                if(isinvalid || islong) {
                    HIFIConfigureFSwitchIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                    islong = false;
                    isinvalid = false;
                }
                HIFIFSwitchOnIntegration(data_time,n_per_on,band,reffreq,onrates);
            }
            // Other frequencies
            // Reset group counter
            i_group = 1;
            if(i_group <= grouplen - 1) {
                if(isinvalid || islong) {
                    HIFIConfigureFSwitchIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                    islong = false;
                    isinvalid = false;
                }
            }
            while(i_group <= grouplen - 1) {
                // retune
                runningfreq = freqgrid[grouporder[i_phase][i_group] + i_freqcycles * grouplen];
                HIFIChangeFreqFsw(band,runningfreq,freq_throw);
                HIFIFSwitchOnIntegration(data_time,n_per_on,band,reffreq,onrates);
                i_group = i_group + 1;
            }
            // Now we switch to the next frequency group or repeat the cycle
            if(state[2] % n_cycles == 0 && i_phase == 1) {
                // Big tuning step, but not at end of observation
                if(state[2] < allsteps) {
                    i_freqcycles = i_freqcycles + 1;
                    runningfreq = freqgrid[grouporder[0][0] + i_freqcycles * grouplen];
                    target = targetnames[i_freqcycles];
                    HIFIRetuneFsw(band,runningfreq,freq_throw,target);
                    runintostate = true;
                } else {
                    // final load measurement if requested
                    if(final_load) {
                        delay(readoutdead);
                        SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,false,eff_resolution{0},data_time,backendreadoutparms);
                        runintostate = true;
                    }
                }
            }
            // Active WBS HK if we have a nod slew without calibration
            if(state[2] % 2 == 0) {
                isinvalid = true;
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load switch
            delay(readoutdead);
            SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,false,eff_resolution{0},data_time,backendreadoutparms);
            isinvalid = true;
            runintostate = false;
        }
        // Danging load - already covered above
        // otherwise the instrument stops halftunelength before the telescope
        if(state[0] == 5) {
            // finished shift of instrument operations relative to pointing command
            runintostate = false;
            HIFICloseObs();
        }
    }
}

// Get dead time for frequency switch
double procedure GetFSwitchDeadTime {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] dead = CalibrationReader("fs_deadtime",["duration"],band,lo_freq);

    return dead[0];
}

//Set LCU3a back to standby status, procedure
procedure LCU3a_standby_proc_fm {
    string band = "3a"; // HIFI band
    double lo_freq = 810.0 in [807.0,848.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

// Compute the additional time needed for HK readout setting at first load
int procedure HkReadoutTime {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
    bool fast = false; //whether fast chop is used
}{
    // get time added already for normal readout
    if(fast) {
        int readoutdead = FastChopReadoutDelay(band,lo_freq,backendreadoutparms);
    } else {
        readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    }
    // HK readout time
    int hkreadouttime = duration(HIFISetHK("normal",false));
    int remain = imax(hkreadouttime - readoutdead,0);

    return remain;
}

// Procedure to compute all parameters needed in a Configure_spectroscopy
{int,int,int,int,int,int,int,int,int,int} procedure ConfigureSpectroscopyParams {
    /* Integration time */
    int data_time = 4; // Integration time between two data readouts
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string chopmode = "chop" in ["chop","lchop","fs","hot-cold","tp"]; // Chop mode determining the modulation dead time
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used,channel windows}
}{
    // Get fixed parameters from configuration and calibration files
    // Command jitter time is the default delay 
    {double,string}[] result = ConfigurationReader("name_delays",["add_jitter"],band,lo_freq);
    int add_jitter = iround(result[0]{0});
    // WBS delta time 
    // Default total power. This should be 0.
    int del_wbs = add_jitter;
    // WBS delta time given by switch dead time
    if(chopmode == "chop") {
        double res = GetSkyChopDeadTime(band,lo_freq);
        del_wbs = iceil(res * 1000.0);
    }
    if(chopmode == "lchop") {
        res = GetLoadChopDeadTime(band,lo_freq);
        del_wbs = iceil(res * 1000.0);
    }
    if(chopmode == "fs") {
        res = GetFSwitchDeadTime(band,lo_freq);
        del_wbs = iceil(res * 1000.0);
    }
    if(chopmode == "hot-cold") {
        bool wbsused = backendreadoutparms{2}{0} || backendreadoutparms{3}{0};
        res = HotColdRelaxTime(band,lo_freq,wbsused);
        del_wbs = iceil(res * 1000.0);
    }
    // HRS delta time - should be zero as well
    int del_hrs = add_jitter;
    // Additional delays in the readout loops - given in OBS user manual
    result = ConfigurationReader("name_delays",["add_hrs","add_wbs","add_jitter","wbs_init","wbs_chunksize","tacc_add","hrs_phase","min_wbs_acc","scos_jitter"],band,lo_freq);
    int add_hrs = iround(result[0]{0});
    int add_wbs = iround(result[1]{0});
    int wbs_init = iround(result[3]{0}) + iround(result[8]{0});
    int wbs_chunksize = iround(result[4]{0});
    int tacc_add = iround(result[5]{0});
    int hrs_phase = iround(result[6]{0});
    // HRS standard phase length
    int min_wbs_acc = iround(result[7]{0});
    // WBS transfer time
    // Split total integration time
    int tint = data_time * n_data * 1000;
    // dead time has to be an integer multiple of the 10ms chunk time
    int tdead = del_wbs + add_wbs + add_jitter;
    int nchunk = (tdead - 1) / wbs_chunksize + 1;
    int tcorr = nchunk * wbs_chunksize - tdead;
    del_wbs = del_wbs + tcorr;
    tdead = tdead + tcorr;
    // Accumulation time
    // Ignores that total power can be slightly more efficient
    int t_acc_wbs = (tint - wbs_init) / n_data - tdead;
    // discretize in 10ms chunks
    nchunk = (t_acc_wbs - tacc_add) / wbs_chunksize;
    t_acc_wbs = nchunk * wbs_chunksize + tacc_add;
    // Check relative to minimum accumulation tim
    if(t_acc_wbs + del_wbs + add_wbs < min_wbs_acc + add_jitter) {
        SError("WBS integration too short for readout. Increase duration.");
    }
    // No WBS addition in ICU
    int n_wbs_integr = 1;
    int n_wbs_start = n_data;
    // HRS
    int hrs_fullphase = hrs_phase + del_hrs + add_hrs;
    int r_hrs = (t_acc_wbs + hrs_fullphase - add_jitter) / hrs_fullphase;
    int t_acc_hrs = (t_acc_wbs - add_jitter) / r_hrs - del_hrs - add_hrs;
    // for n_wbs_integr=1 identical to r_hrs
    int n_hrs_integr = r_hrs;
    // Compute actual integration time and dead time per readout
    // If WBS is used count only the WBS time
    if(backendreadoutparms{2}{0} || backendreadoutparms{3}{0}) {
        int tint_act = nchunk * wbs_chunksize * n_data;
        tdead = tdead + tacc_add;
    } else {
        tint_act = t_acc_hrs * r_hrs * n_data;
        tdead = tdead + r_hrs * (del_hrs + add_hrs) + add_jitter;
    }
    // Return all config_spectroscopy timing parameters

    return {n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,tdead,tint_act};
}

// Check frequency throw relative to HRS bandwidth
procedure CheckFswOutOfBand {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
}{
    bool hrs1used = backendreadoutparms{0}{0};
    // HRS1 to be used
    int hrs1resol = backendreadoutparms{0}{1};
    // resolution
    bool hrs2used = backendreadoutparms{1}{0};
    // HRS2 to be used
    int hrs2resol = backendreadoutparms{1}{1};
    // resolution
    // get minimum bandwidth covered 
    // Start from full IF
    double bw = GetBackendBandwidth(band,lo_freq,-1);
    // Both HRS
    if(hrs1used) {
        double hbw = GetBackendBandwidth(band,lo_freq,hrs1resol);
        bw = min(bw,hbw);
    }
    if(hrs2used) {
        hbw = GetBackendBandwidth(band,lo_freq,hrs2resol);
        bw = min(bw,hbw);
    }
    // Compare with frequency throw
    if(abs(freq_throw) > 0.5 * bw) {
        // Generate messages - first close previous paragraph	   
        message("</p>");
        message("<h3>Warning</h3>");
        message("<p>");
        message("The chosen frequency throw of " + freq_throw + " MHz is large " + "compared to the HRS subband coverage. It is likely that the HRS " + "does not see some lines in both frequency-switch phases. In this " + "case, the actual S/N ratio will be lower by a factor two than the " + "predicted one.");
    }
}

//TM to control FDIR on LOU temp.
block LO_Temp_FDIR_block_fm HIFI 3952 {
    string activate = "ON" in ["ON","OFF"]; //Whether FDIR is activated or not
    double tmin = 123.0; //Min threshold
    double tmax = 145.0; //Max threshold
    int nbreach = 10; //Number of breach
}{
    Start_block();
    if(activate == "OFF") {
        Hifi_HIFI_LOU_T_check_off();
    } else {
        Hifi_HIFI_LOU_T_check_on(nbreach,tmax,tmin);
    }
    delay(1);
    //
}

// Fast chop integration OFF-ON-OFF-ON... with telescope at OFF position
block HIFIFastHalfChopOffIntegration HIFI 6054 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // readout cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int[] parms = [1,0]; // Parameters for chop cycles
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_fast_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_M3","chop_M3right"],parms,rates);
}

// Procedure to get timing in a spectroscopy measurement
{double,double} procedure GetInstDeadFastChop {
    /* Integration time */
    int data_time = 10 in [4,128]; // data dump interval
    int n_int = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used,channel windows}
}{
    // Get timing parameters
    bool wbs_used = backendreadoutparms{2}{0} || backendreadoutparms{3}{0};
    {int,int,int,int,int,int,int,int,int,int,int,int,int} timing = FastConfigureSpectroscopyParams(data_time,n_int,n_data,band,lo_freq,wbs_used);
    int tdead_chop = timing{10};
    int tdead_data = timing{11};
    int tint = timing{12};
    // For the noise computation there is no difference between initial dead
    // and readout dead, they are all summed up
    // Return dead time per full integration
    double tintall = double(tint) / 1000.0;
    double tdeadphase = double(tdead_chop) / 1000.0;

    return {tintall,tdeadphase};
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The blocks
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Write EEPROM , block
block Write_EEPROM_block_ops HIFI 7930 {
}{
    mois_step("Write on EEPROM partition of relevance");
    mois_spacon("Ask the HIFI support on which partition on the EEPROM the software must be written (either 1 or 2). The answer to this question corresponds to the formal parameter HP228197 (= hifi_HIF_partition_ID) of the next command.");
    mois_spacon("Similarly, ask the HIFI support which end address should be used (in consistency with applicable issue of SRON_U/HIFI/PR/2007-007). The answer to this question corresponds to the formal parameter HP005197 (= hifi_OBS_mem_end) of the next command.");
    //
    int hifi_OBS_mem_end = 0x185c1;
    //this is applicable to OBS5.8.1.
    int hifi_HIF_partition_ID = 1;
    int hifi_HIF_Npages_to_skip = 0;
    Hifi_HIFI_eeprom_write(hifi_OBS_mem_end,hifi_HIF_partition_ID,hifi_HIF_Npages_to_skip,[]);
    delay(1);
    mois_spacon("Please log the partition and end address that were used, together with the OBSW version");
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// FM CUS scripts to assess various instrument settling
// times (CAL UC-1.1.2)
//
// DT - 27 Oct 2005: first draft based on CAL UC doc.
//
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//modes: see fm_testmodes.cus
///////////////////////////////////
// Procedures
///////////////////////////////////
// Chopper Response time with user input choice on angle, block
block Chopper_Response_time_EXPERT_block_fm HIFI 3686 {
    double targetAngle = 0.1; // angle to move to
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50];
    int samplesAfter = 100 in [0,1000];
}{
    Start_block();
    //
    targetAngle = Check_Chopper_Prime_Redundant(targetAngle);
    HIFI_Chopper_scan_fast_proc_fm(milliSecSample,targetAngle,samplesBefore,samplesAfter);
    //
    // delay calculation TBC
    int millisecondsUsed = 500 + milliSecSample * (samplesBefore + samplesAfter + 1);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //
}

//HIFI-COP-X-IF-FBk-Cal
obs HifiEng_IF_FBk_Cal_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string chopcase = "dbs" in ["dbs","csa","lsw"]; //chopper delta considered
    int testtime = 3600; //total test time in seconds
}{
    //General parameters in use
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result_d[0];
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //  
    //Avoid high data-rates
    if(testtime % 3 == 0 && testtime % 4 == 0) {
        testtime = testtime + 4;
    }
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(IF_FBk_Cal_COP_proc_ops(band,lo_freq,hrs_mode,testtime,backend,chopcase));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            IF_FBk_Cal_COP_proc_ops(band,lo_freq,hrs_mode,testtime,backend,chopcase);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

{string,double,double}[] procedure HifiPointModeFSwitchNoRefSequencerInit {
    string modeName = "fs";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_cycles = 2 in [1,3600]; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // inherit from load-chop mode
    {string,double,double}[] retvalues = HifiPointProcLoadChopNoRefSequencerInit(naifid,ra,dec,band,lo_freq,effResolution,oneGHzReference,hrs1,hrs2,wbs1,wbs2,data_time,n_cycles,load_interval,docommands);

    return retvalues;
}

//Contingency for LOU temp FDIR modification
mode HifiManCmd_LOU_FDIR_disable {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    mois_comment("Procedure to disable the FDIR on limits for LOU operational temperatures");
    //StartMode_block_ops(); 
    //
    mois_step("Disable FDIR");
    Disable_LO_FDIR_temperatures_block_mois();
    //
    StopMode_block_ops();
    // -> to issue last obsd/bbid
}

// Needs the chopper in open-loop mode !!
block Chopper_openloop_scan_block_fm HIFI 3694 {
    int scan_portion = 1 in [1,3]; //indicates which part of scans is to be done
}{
    //Start_block ();
    //Hard-coded RAW values for end stops and rest position 
    int low = 1298;
    //This is slightly further the low end-stop
    int high = 2548;
    //This is slightly further the high end-stop
    int zero = 2048;
    //This is the zero position
    int step = 50;
    //
    int chopper_pos = zero;
    //Scan from zero to end-stop high
    while(chopper_pos <= high) {
        if(scan_portion == 1) {
            HIFI_CPR_Chopper_Rot_RAW_proc_fm(chopper_pos);
            //Rotate chopper
            Hifi_HIFI_non_periodic_hk_FCU();
            //To get sent value
            delay(2);
        }
        chopper_pos = chopper_pos + step;
    }
    //Scan from end-stop high to end-stop low
    chopper_pos = high - step;
    while(chopper_pos >= low) {
        if(scan_portion == 2) {
            HIFI_CPR_Chopper_Rot_RAW_proc_fm(chopper_pos);
            //Rotate chopper
            Hifi_HIFI_non_periodic_hk_FCU();
            //To get sent value
            delay(2);
        }
        chopper_pos = chopper_pos - step;
    }
    //Scan from end-stop low to zero
    chopper_pos = low + step;
    while(chopper_pos <= zero) {
        if(scan_portion == 3) {
            HIFI_CPR_Chopper_Rot_RAW_proc_fm(chopper_pos);
            //Rotate chopper
            Hifi_HIFI_non_periodic_hk_FCU();
            //To get sent value
            delay(2);
        }
        chopper_pos = chopper_pos + step;
    }
}

// Load calibration measurement
procedure LoadMeasurement_FCal {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double lo_freq = 978200.0; // LO frequency
    double deltanu = 1.0; // minimum effective resolution of the calibrated data
    int data_time = 4; // time between subsequent data readouts
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
}{
    // Initial computations
    {int,int,bool} calinit = HIFICalInit(band,lo_freq,deltanu,data_time);
    int used_datatime = calinit{0};
    int n_inttime = calinit{1};
    bool retuning = calinit{2};
    // Perform zero and comb measurement
    ZeroCombMeasurement_FCal(band,lo_freq,used_datatime,backendreadoutparms);
    // No we perform the actual hot-cold measurement
    // slow_chop_spectroscopy
    int danglingreadout = HIFI_Calibrate_hot_cold(band,lo_freq,used_datatime,n_inttime,backendreadoutparms,retuning);
    // Retune and another load if we are in HEB bands
    if(retuning) {
        // we have to wait for readout
        delay(danglingreadout);
        // Another LO vector scan at the same frequency for a stable HEB operation
        HIFITuneFreq(band,lo_freq,false,"");
        danglingreadout = HIFI_Calibrate_hot_cold(band,lo_freq,used_datatime,n_inttime,backendreadoutparms,false);
    }
}

//Procedure checking the consistency of slow chop spectroscopy
//parameters to be sent to configuration command.
bool procedure Check_slow_chop_parameters_proc {
    int n_wbs_start = 4; //Nb of frames
    int r_hrs = 1; //Nb of HRS readout per WBS readout
    int n_wbs_integr = 1; //Number of wbs readout packetized per WBS frame
    int n_hrs_integr = 1; //Number of hrs readout packetized per HRS frame
    int del_hrs = 5; //Delay before starting HRS integration
    int del_wbs = 5; //Delay before starting WBS integration
    int t_acc_wbs = 4005; //Duration of WBS frame 
    int t_acc_hrs = 1950; //Duration of HRS frame
    int wbsh_offset1 = 0;
    int wbsh_width1 = 2048;
    int wbsh_offset2 = 2048;
    int wbsh_width2 = 2048;
    int wbsh_offset3 = 4096;
    int wbsh_width3 = 2048;
    int wbsh_offset4 = 6144;
    int wbsh_width4 = 2048;
    int wbsv_offset1 = 0;
    int wbsv_width1 = 2048;
    int wbsv_offset2 = 2048;
    int wbsv_width2 = 2048;
    int wbsv_offset3 = 4096;
    int wbsv_width3 = 2048;
    int wbsv_offset4 = 6144;
    int wbsv_width4 = 2048;
    int hrs_rshift = 0; //HRS bit shift
    int wbs_rshift = 0; //WBS bit shift
    int hrsh_sel = 255; //HRS-H band selection
    int hrsv_sel = 255; //HRS-V band selection
    string wbs_packing = "24_bits_format";
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    error("Procedure Check_slow_chop_parameters_proc is not used anymore.");

    return false;
}

// Standing wave study for FSW model
//HIFI-COP-X-StWv-FSW
obs HifiEng_StWv_FSW_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(StWv_FSW_COP_proc_ops(band));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            StWv_FSW_COP_proc_ops(band);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// Third part of FPSS FM functional test, block
// Magnet scan fine, around expected optimal magnets
// This differs from Magnet_scan_fine which scans over
// the whole range.
block FT_FPU_magnet_tune_fine_fm HIFI 3802 {
    string band = "1a";
    double magnet_current_h = -5.7; //Central magnet current H
    double magnet_current_v = -9.4; //Central magnet current H
    double step_current = 0.1; //Current increment in mA
    int step_number = 10; //Number of steps
    int integ_time = 4; //Integation time in seconds
    double lo_freq = 500.0; //LO frequency
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //Get nominal biases and magnets
    {double,string}[] result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_h = result[0]{0};
    double bias_v = result[1]{0};
    //
    //H polar
    double magnet_min_h = magnet_current_h - step_current * double(step_number) / 2.0;
    double magnet_max_h = magnet_current_h + step_current * double(step_number) / 2.0;
    //V polar
    double magnet_min_v = magnet_current_v - step_current * double(step_number) / 2.0;
    double magnet_max_v = magnet_current_v + step_current * double(step_number) / 2.0;
    //
    double magnet_min = max(magnet_min_h,magnet_min_h);
    double magnet_max = min(magnet_max_h,magnet_max_h);
    //
    double step_duration = 0.1;
    int steps = 0;
    int steps_done = 0;
    int max_per_command = 40;
    //
    int steps_wanted = step_number;
    //  
    double step = Stepsize(magnet_min,magnet_max,steps_wanted,"hifi_HIF_mx_mg_step_C");
    double margin = Stepmargin(magnet_min,magnet_max,"hifi_HIF_mx_mg_step_C");
    steps_wanted = 1 + iceil((magnet_max - magnet_min) / step);
    // force the last portion to less than max_per_command
    if(max_per_command * (steps_wanted / max_per_command) == steps_wanted) {
        steps_wanted = steps_wanted - 1;
    }
    //
    //Set magnet to maximum to avoid hysteresis
    result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
    Hifi_HIFI_CH1_MX_MG_C($BBID,result[0]{0});
    Hifi_HIFI_CV1_MX_MG_C($BBID,result[1]{0});
    delay(2);
    //
    magnet_current_h = magnet_min_h;
    magnet_current_v = magnet_min_v;
    while(steps_done < steps_wanted) {
        steps = steps_wanted - steps_done;
        if(steps > max_per_command) {
            steps = max_per_command;
        }
        magnet_current_h = magnet_min_h + double(steps_done) * step;
        magnet_current_v = magnet_min_v + double(steps_done) * step;
        Hifi_HIFI_FCU_parameter_scan($BBID,1,1,step_duration,bias_h,bias_v,0.0,magnet_current_h,magnet_current_v,0.0);
        delay(2);
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
        steps_done = steps_done + 1;
    }
}

//HIFI-COP-1.2-LO_FT: for MTL in routine: uses single TM page TC
procedure LO_FT_COP_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_comment("Start of HIFI LO Functional Test for band " + band);
    mois_comment("Please check that instrument was switched on with the " + prime_or_redundant + " unit");
    mois_tmcheck("Check content of AND LCU_temperatures_with HIFI expert.");
    //General parameters in use
    string multiplier = "ALL";
    int operation_delay = 0;
    //
    double[] cresult_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = cresult_d[0];
    //applies to cold LO
    //
    mois_step("Init MSA");
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    Init_MSA_ops(band,"CLOSE",lo_freq,result[0]{0},"ON",prime_or_redundant);
    //
    //First switch off the band.
    LCU_switch_off_block_fm();
    mois_tmcheck("Check that parameter HL_Channel_S is OFF");
    //
    mois_step("Measure LCU IV curve");
    Measure_LCU_IV_proc_fm(band,multiplier,operation_delay);
    //
    //Switch on with safe Vd2
    mois_step("Switch on LO band");
    LCU_switchon_proc_fm(band);
    mois_tmcheck("Check that parameter HL_MODE_S is normal");
    mois_tmcheck("Check that parameter HL_Channel_S is " + band);
    //
    mois_step("LO SFT");
    //This will switch on the chain again
    LO_SFT_proc_ops(band,prime_or_redundant);
    //
    mois_tmcheck("Check whether parameter HL_error_word_S has been FAULT at any time of the procedure. Communicate occurences to HIFI expert.");
    mois_tmcheck("Check content of AND LCU_status2 and LCU_" + band + " with HIFI expert.");
}

/////////////////////////////////////////////////////////////////
// Spectral scan in DBS observing modes
// 
{string,double,double}[] procedure HifiSScanProcDBSSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hr1{0},hr1{1},hr1{3}},{hr2{0},hr2{1},hr2{3}},wb1,wb2};
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    // Now general part of DBS modes
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // Get the drift parameters to compute the drift noise
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {double,double} phaselengths = DBSPhaseLengths(band,reffreq,effResolution,continuumDetection,narrowReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // remaining part for n_switch
    int n_switch_on_guess = iceil(phaselengths{0}) / (n_freq_point_guess * 2 * data_time_guess) + 1;
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)}];

    return retvalues;
}

//HIFI HK control, block
block Switch_HK_block_ops HIFI 7605 {
    string hk_FCU = "ON" in ["ON","OFF"]; //Status of FCU HK
    string hk_LCU = "ON" in ["ON","OFF"]; //Status of LCU HK
    string hk_WBSV = "ON" in ["ON","OFF"]; //Status of WBSV HK
    string hk_WBSH = "ON" in ["ON","OFF"]; //Status of WBSH HK
    string hk_HRSV = "ON" in ["ON","OFF"]; //Status of HRSV HK
    string hk_HRSH = "ON" in ["ON","OFF"]; //Status of HRSH HK
}{
    StartBlock_ops();
    //Get applicable HK rate
    {double,string}[] result_d = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    string hk_rate = result_d[0]{1};
    Hifi_HIFI_Housekeeping_on(hk_rate,hk_FCU,hk_LCU,hk_WBSV,hk_WBSH,hk_HRSV,hk_HRSH);
    delay(1);
}

// Fast chop integration OFF-ON-OFF-ON... with telescope at ON position
block HIFIFastHalfChopOnIntegration HIFI 6053 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // readout cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int[] parms = [1,0]; // Parameters for chop cycles
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_fast_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_M3","chop_M3right"],parms,rates);
}

{string,double,double}[] procedure HifiMappingModeOTFSequencerInit {
    string modeName = "fly";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,5]; // chunk size given by the data rates and optimum speed
    int n_int_on = 1 in [1,1800]; // Supersamplingfactor
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // Compute derived quantities
    int main_phase = iceil(0.3 * allan_time_lores);
    // How many lines could we do at most using datalimit?
    int n_linesperscan_guess = main_phase / datalimit + 1;
    n_linesperscan_guess = imax(n_linesperscan_guess * n_linesperscan_guess / npoints,1);
    // restrict the scan size
    if(nlines == 1 && n_linesperscan_guess > 1) {
        n_linesperscan_guess = 2;
    } else {
        n_linesperscan_guess = IMultiple(n_linesperscan_guess,nlines);
        n_linesperscan_guess = imin(n_linesperscan_guess,nlines);
    }
    int n_linesperscan_range = 1 - n_linesperscan_guess;
    if(n_linesperscan_range == 0) {
        n_linesperscan_range = 1;
    }
    double n_pointsperscan = double(n_linesperscan * npoints);
    // Compute back
    int int_time_guess = imax(main_phase / iceil(sqrt(n_pointsperscan)),datalimit);
    int data_time_guess = imin(5,int_time_guess);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_int_on_guess = imax(int_time_guess / data_time_guess,1);
    int n_int_on_range = 1 - n_int_on_guess;
    if(n_int_on_range == 0) {
        n_int_on_range = 1;
    }
    // OFF integration
    int n_switch_off_guess = ifloor(double(n_int_on) * 0.67 * sqrt(n_pointsperscan));
    int n_switch_off_range = n_switch_off_guess / 3;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_int_on",double(n_int_on_guess),double(n_int_on_range)},{"n_linesperscan",double(n_linesperscan_guess),double(n_linesperscan_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)}];

    return retvalues;
}

/////////////////////////////////////////////////////////////////
// Get valid table range
{int,int} procedure GetFScanBoundaries {
    string band = "4a"; // HIFI band
    double freq_throw = -40.0; // throw of frequency switch in MHz
}{
    // read master file
    string calibfile = slookup("frequencystep_masterfile",band,"tablefile");
    double[] allfpoints = dcolumn(calibfile,"stepfrequency");
    // get table size
    int iindex1 = length(allfpoints);
    if(freq_throw < 0.0) {
        int istart = 1;
        int iend = iindex1 - 2;
        double goallo = allfpoints[1] - freq_throw;
        while(allfpoints[istart] < goallo) {
            istart = istart + 1;
        }
    } else {
        istart = 1;
        iend = iindex1 - 2;
        goallo = allfpoints[iindex1 - 2] - freq_throw;
        while(allfpoints[iend] > goallo) {
            iend = iend - 1;
        }
    }

    return {istart,iend};
}

//Chopper health check test #1 of chopper during open loop, mode
mode HifiManCmd_Chopper_openloop_set_health_check {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_tmcheck("The instrument should be in Standby I mode in open loop context for this test");
    //It is done after chopper has been switched on in open loop
    mois_tmcheck("The instrument must have been switched on with its " + prime_or_redundant + " electronics");
    mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to OPEN");
    mois_tmcheck("Check that parameter HF_DPR_CHSINE_S is set to ON");
    //
    mois_comment("Performing part one of HIFI internal chopper health check");
    StartMode_block_ops();
    //Prepare LVDT readout check
    double c0 = -1.09;
    double err_C0 = 0.2;
    double c1 = 1.58;
    double err_C1 = 0.08;
    double err_C0_2 = 0.04;
    if(prime_or_redundant == "Redundant") {
        c0 = -2.315;
        err_C0 = 0.2;
        c1 = 1.555;
        err_C1 = 0.08;
        err_C0_2 = 0.4;
    }
    //Go to 2048 RAW
    Chopper_openloop_set_block_ops(0,prime_or_redundant);
    mois_tmcheck("Check that parameter HF_APR_CH_ROT is " + c0 + "V +/- " + err_C0 + "V. If not stop test and contact the HIFI ICC");
    //Go to 2118 RAW
    Chopper_openloop_set_block_ops(1,prime_or_redundant);
    mois_tmcheck("Check that parameter HF_APR_CH_ROT has decreased by " + c1 + "V +/- " + err_C1 + "V with respect to its readout value at the previous step. If not stop test and contact the HIFI ICC");
    //Back to 2048 RAW
    Chopper_openloop_set_block_ops(0,prime_or_redundant);
    mois_tmcheck("Check that parameter HF_APR_CH_ROT is " + c0 + "V +/- " + err_C0_2 + "V. If not stop test and contact the HIFI ICC");
    //
    StopMode_block_ops();
    mois_spacon("Write down the OBS_ID corresponding to this mode and communicate it to the HIFI ICC");
}

//FSW hotcold, procedure
procedure Hot_cold_FSW_fm {
    string band = "1a";
    int integ_time = 8; //Total integration time for delay computation
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast 
}{
    Hot_spectra_FSW_fm(band,integ_time,backend);
    Cold_spectra_FSW_fm(band,integ_time,backend);
}

// WBS stand-by, block
block WBS_standby_block_ops HIFI 7703 {
    string band = "0"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
}{
    //Get default latchup level
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_latchup_s","hwv_latchup_s"],"0",0.0);
    //
    //Set zero ON
    Hifi_HIFI_switch_zero_WBS_H($BBID,"ON");
    Hifi_HIFI_switch_zero_WBS_V($BBID,"ON");
    delay(1);
    //Will be done at end of procedure during instrument mode status check
    //mois_tmcheck("Check that parameter HWH_Zero_S is ON");
    //mois_tmcheck("Check that parameter HWV_Zero_S is ON");
    //Standby configuration
    //H-Polarization
    //
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = 0;
    //000
    string hwh_latchup_s = result_d[0]{1};
    int hwh_att_band4 = 7;
    int hwh_att_band3 = 7;
    int hwh_att_band2 = 7;
    int hwh_att_band1 = 7;
    int hwh_att_in = 15;
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    {double,string}[] result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = 0;
    //000
    string hwv_latchup_s = result_d[1]{1};
    int hwv_att_band4 = 7;
    int hwv_att_band3 = 7;
    int hwv_att_band2 = 7;
    int hwv_att_band1 = 7;
    int hwv_att_in = 15;
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Will be done at end of procedure during instrument mode status check
    //mois_tmcheck("Check that parameter HWH_Laser1_S is " + hwh_laser1_s);
    //mois_tmcheck("Check that parameter HWH_Laser2_S is " + hwh_laser2_s);
    //mois_tmcheck("Check that parameter HWV_Laser1_S is " + hwv_laser1_s);
    //mois_tmcheck("Check that parameter HWV_Laser2_S is " + hwv_laser2_s);
    //mois_tmcheck("Check that parameter HWH_IN_ATT is set to 15, and parameters HWH_Band_1_ATT, HWH_Band_2_ATT, HWH_Band_3_ATT, HWH_Band_4_ATT are set to 7");
    //mois_tmcheck("Check that parameter HWV_IN_ATT is set to 15, and parameters HWV_Band_1_ATT, HWV_Band_2_ATT, HWV_Band_3_ATT, HWV_Band_4_ATT are set to 7");
}

// Fast chop integration OFF-ON-OFF-ON... with telescope at OFF position
block HIFIFastChopOffIntegration HIFI 6043 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // readout cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int[] parms = [1,0]; // Parameters for chop cycles
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_fast_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_M3left","chop_M3right"],parms,rates);
}

//////////////////////////////////////////////////////////////////////////
// Procedure to generate the composite position telescope command for the 
// observing mode
{int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} procedure PositionSwitch_telescope {
    int naifid = 0; // Tracking object ID
    {double,double} onposition = {0.0,0.0}; // Coordinates of the source
    {double,double} offposition = {0.2,0.2}; // Coordinates of the OFF position
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} timing = {16,16,16,16,21,11,1800,32,2,2,0,0,false,false,50,0};
    int n_cycles = 2; // Number of half OFF-ON-ON-OFF cycles
}{
    // Assign values
    int on_pointing = timing{2};
    // Pointing on on-position
    int off_pointing = timing{3};
    // Pointing OFF on-position
    int loadlength = timing{4};
    // Load duration
    int n_loadinterval = timing{7};
    // Number of nods between load measurements
    int initlength = timing{14};
    // Initial setup time
    int dangling = timing{15};
    // Final load measurement
    // Create variables for telescope command
    string ib = GetBoresight(band,lo_freq,false);
    // A change of ra-dec depending on naifid may be needed
    double ra = onposition{0};
    double dec = onposition{1};
    // Compute offset: This is always in sky coordinates
    {double,double} offset = AngularOffset(onposition,offposition);
    double patt = AngleFromVector(offset);
    double slewlength = AngleVectorLength(offset);
    slewlength = max(slewlength * 3600.0,2.0);
    // Check parameter compatibility with pointing command for parameters
    // which are no direct input parameters
    if(on_pointing < 10) {
        SError("Source pointing phase length too short. Increase the number of integrations.");
    }
    if(off_pointing < 10) {
        SError("OFF pointing phase length too short. Increase the number of integrations.");
    }
    if(slewlength > 7200.0) {
        IError("Slew distance too long. Choose a closer OFF position.");
    }
    // repetition at multiple frequencies not yet implemented:
    int thold = 0;
    int nhold = 0;
    int n_repeat = n_cycles;
    // return parameters in required order

    return {initlength,0,dangling,ib,naifid,ra,dec,true,patt,0.0,0.0,n_repeat,slewlength,on_pointing,off_pointing,loadlength,n_loadinterval,thold,nhold};
}

// Drift noise from an asymmetric two-phase observation
// This is still to be scaled by a factor 1.0/(B_fluct_A*T_Allan)
double procedure AsymmetricDrift {
    double xa = 0.1; // integration time in phase A relative to Allan time
    double xb = 0.1; // integration time in phase B relative to Allan time
    double d = 0.3; // delay relative to Allan time
    double alpha = 2.5; // drift exponent 
}{
    if(xa >= 0.0) {
        double a1 = alpha + 1.0;
        double y = ((pow(xa + xb + d,a1) - pow(xa + d,a1) - pow(xb + d,a1) + pow(d,a1)) / (xa * xb) - pow(xa,a1) / (xa * xa) - pow(xb,a1) / (xb * xb)) / (pow(2.0,alpha) - 2.0);
    } else {
        // forbid x values <=0
        y = 1.0E11 * (1.0 - xa);
    }

    return y;
}

// Drift noise from a symmetric two-phase observation
// This is still to be scaled by a factor 1.0/(B_fluct*T_Allan)
double procedure TwoPhaseDrift {
    double x = 0.1; // integration time relative to Allan time
    double d = 0.3; // delay relative to Allan time
    double alpha = 2.5; // drift exponent 
}{
    if(x >= 0.0) {
        double a1 = alpha + 1.0;
        double y = (pow(2.0 * x + d,a1) - 2.0 * pow(x + d,a1) + pow(d,a1) - 2.0 * pow(x,a1)) / ((pow(2.0,alpha) - 2.0) * x * x);
    } else {
        // forbid x values <=0
        y = 1.0E11 * (1.0 - x);
    }

    return y;
}

// Take total power spectra, block
// Use AOT efficient timing
block Spectro_total_power_AOTLike_block_fm HIFI 3930 {
    string band = "1a"; // HIFI band
    int[] timing_parms = [4,1]; //single readout time in sec. and n_wbs_start
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    int integ_time = timing_parms[0] * timing_parms[1];
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"tp",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    Hifi_HIFI_Spectr_total_power($BBID);
    delay(integ_time);
    //
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

///////////////////////////////////////////////////////
// Generic procedures to tune S/S in HIFI
// Set magnet currents for both polarizations, procedure
procedure Set_Magnet_current_proc_fm {
    double mag_curr_h = 1.0; //Magnet current H polarization
    double mag_curr_v = 1.0; //Magnet current V polarization
}{
    Hifi_HIFI_CH1_MX_MG_C($BBID,mag_curr_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,mag_curr_v);
    delay(1);
}

// Integrate only on internal hot, block
// We take 1 spectrum per phase.
block Stability_inthot_fm HIFI 3425 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integrations
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string obsmode = "fastchop" in ["fastchop","tp"]; //tp or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    Start_block();
    Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_hot_ang");
    //Look at HBB
    //Get chopper settings
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_hot"],band,0.0);
    double chop_hot = result[0]{0};
    //Do a long integration: 
    //	- for B1-5, use 2 sec. with wbs or hrs only, thus tp is OK
    //  - for B6: use 1 sec. with reduced wbs (wbsFast), thus tp is OK
    //We implement a special spectroscopy configuration with fixed values
    if(obsmode == "tp") {
        Total_power_spectro_for_Stability_proc_fm(band,n,integ_time,backend,hrs_mode);
    }
    if(obsmode == "fastchop") {
        Fast_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_hot,chop_hot,chop_phase);
    }
}

//HIFI LO tuning, block
//Target current is read from look-up table
block LO_tuning_block_fm HIFI 3616 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    string mixer_polarization = result[0]{1};
    //
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlcu = "name_configlcu_a";
    string name_configlo = "name_configlo_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlcu = "name_configlcu_b";
        name_configlo = "name_configlo_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double middle_d2 = result[0]{0};
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    //
    //delay(5);	//to settle at this value
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//LCU IV curves, procedure
procedure Measure_LCU_IV_proc_fm {
    string band = "1a" in ["ALL","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string multiplier = "M1" in ["ALL","M1","M2","M3"]; //Multiplier to be measured: M1, M2 or M3
    int operation_delay = 60; //When ALL is selected, Waiting delay between two measurements on a band (e.g. to change connector)
}{
    //
    //Array of names
    string[] band_array = ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"];
    string[] multiplier_array = ["M1","M2","M3"];
    //
    //Case of all bands done
    string band_loop = "1a";
    string multiplier_loop = "M1";
    //
    if(band == "ALL") {
        //loop on bands
        for(int i = 1 .. 14) {
            //Translate band name
            band_loop = band_array[i - 1];
            if(multiplier == "ALL") {
                for(int j = 1 .. 3) {
                    multiplier_loop = multiplier_array[j - 1];
                    Measure_LCU_IV_block_fm(band_loop,multiplier_loop);
                }
            } else {
                Measure_LCU_IV_block_fm(band_loop,multiplier);
            }
            delay(operation_delay);
        }
    } else {
        //do only one band
        if(multiplier == "ALL") {
            for(int k = 1 .. 3) {
                multiplier_loop = multiplier_array[k - 1];
                Measure_LCU_IV_block_fm(band,multiplier_loop);
            }
        } else {
            Measure_LCU_IV_block_fm(band,multiplier);
        }
        delay(operation_delay);
    }
    //
}

//Get blue min
double procedure Get_BLUE_MIN_D2_proc_fm {
    string band = "4a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band   
    double lo_freq = 978.2; //LO Frequency
}{
    //Anticipated implementation of SCR-2220
    string name_configlcu = "name_configlcu_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlcu = "name_configlcu_b";
    }
    {double,string}[] result = ConfigurationReader(name_configlcu,["drain2_v_blmn","drain2_v_blmx"],band,lo_freq);
    double drain2_min = 0.0;
    if(band == "1a") {
        drain2_min = result[0]{0};
    }
    if(band == "1b") {
        drain2_min = result[0]{0};
    }
    if(band == "2a") {
        drain2_min = result[0]{0};
    }
    if(band == "2b") {
        drain2_min = result[0]{0};
    }
    if(band == "3a") {
        drain2_min = result[0]{0};
    }
    if(band == "3b") {
        drain2_min = result[0]{0};
    }
    if(band == "4a") {
        drain2_min = result[0]{0};
    }
    if(band == "4b") {
        drain2_min = result[0]{0};
    }
    if(band == "5a") {
        drain2_min = result[0]{0};
    }
    if(band == "5b") {
        drain2_min = result[0]{0};
    }
    if(band == "6a") {
        drain2_min = result[0]{0};
    }
    if(band == "6b") {
        drain2_min = result[0]{0};
    }
    if(band == "7a") {
        drain2_min = result[0]{0};
    }
    if(band == "7b") {
        drain2_min = result[0]{0};
    }

    return drain2_min;
}

////////////////////////////////////
// Fast chop DBS raster  - cross observing mode
// 
{string,double,double}[] procedure HifiMappingProcFastDBSCrossSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the two raster lines
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power levels
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // inherit from dbs-raster mode
    {string,double,double}[] retvalues = HifiMappingProcFastDBSRasterSequencerInit(naifid,ra,dec,{0.0,double(npoints / 2) * stepsize},2,stepsize,npoints,band,lo_freq,effResolution,continuumDetection,oneGHzReference,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);

    return retvalues;
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The blocks
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Integration on Internal cold, block
block Cold_spectra_fm HIFI 3222 {
    string band = "1a";
    int integ_time = 4; //Total integration time in sec.: at least 2sec !
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //Rotate chopper: assume we come from M3
    Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_cold_ang");
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
}

////////////////////////////////////
// Routine to provide initial guesses for sequence parameters
// Load chop mode without baseline calibration
//
{string,double,double}[] procedure HifiPointProcLoadChopNoRefSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_cycles = 2 in [1,3600]; // number of half load-sky-sky-load cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(0.3 * allan_time_lores),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // Contruct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)}];

    return retvalues;
}

//Set DC bias without switching on the chain, block
//All input parameters shall be given by the user
block LCU_DC_health_check_block_fm HIFI 3699 {
    string band = "1a" in ["ALL","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double plevel_v = 0.0; // HL_PL_C
    double m1_v = 0.0; // HL_M1_V
    double m2_v = 0.0; // HL_M2_V
    double m3_v = 0.0; // HL_M3_V
    double gate1_v = 0.0; // HL_Gate1_V
    double gate2_v = 0.0; // HL_Gate2_V
    double drain1_v = 0.0; // HL_Drain1_V
    string curlim1_v = "1.5" in ["1.5","1.3","1.22","1.4"]; // HL_Curlim1
    double drain2_v = 0.0; // HL_Drain2_1A_V
    string curlim2_v = "1.5" in ["1.5","1.3","1.22","1.4"]; // HL_Curlim2  
}{
    //
    //Start_block();
    //
    //Execute configuration
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_diag_LCU_ch1a($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_diag_LCU_ch1b($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_diag_LCU_ch2a($BBID,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_diag_LCU_ch2b($BBID,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_diag_LCU_ch3a($BBID,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_diag_LCU_ch3b($BBID,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_diag_LCU_ch4a($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_diag_LCU_ch4b($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_diag_LCU_ch5a($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_diag_LCU_ch5b($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_diag_LCU_ch6a($BBID,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_diag_LCU_ch6b($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_diag_LCU_ch7a($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_diag_LCU_ch7b($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    //
    //Then need to switch on band
    string band_new = Translate_band_name(band);
    Hifi_HIFI_HL_switchon($BBID,"channel_" + band_new);
    //
    {double,string}[] result = ConfigurationReader("name_delays",["switch_on_delay"],"0",0.0);
    int switch_on_delay = iround(result[0]{0});
    delay(switch_on_delay);
    //
    //Switch off band to prepare for next band
    Hifi_HIFI_HL_Switch_off($BBID);
    //
    result = ConfigurationReader("name_delays",["switch_off_delay"],"0",0.0);
    int switch_off_delay = iround(result[0]{0});
    delay(switch_off_delay);
}

// Noise ratio from an OTF observation
// 
double procedure OtfNoiseRatio {
    double n = 10.0; // number of points in one scan
    double[] parameters = [0.02,0.4,0.05,0.667,2.5]; // Parameters: integration time, delay, slew from OFF relative to Allan time, ratio of t_off time to sqrt(n)*t_on, drift exponent
}{
    {double,double} noisevalues = OtfNoiseValues(n,parameters);
    double y = noisevalues{1} / noisevalues{0};

    return y;
}

// Slow chop integration at OFF position ON-OFF-OFF-ON...
block HIFISlowChopOffIntegration HIFI 6032 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_slow_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_M3left","chop_M3right"],rates);
}

// Procedure used by the spectral scan sequencer to compute the
// maximum frequency group length
int procedure SpotSpectralScanGroupLength {
    string band = "4a";
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    int redundancy = 4;
}{
    // start Volkers list
    double lo_freq = 978200.0;
    // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0;
    // Upper LO frequency limit in MHz
    // general definitions
    double factorMHzPerGHz = 1000.0;
    // start translation
    lo_freq = lo_freq1 * factorMHzPerGHz;
    lo_freq_up = lo_freq2 * factorMHzPerGHz;
    // Call CUS routine
    int grouplen = GetSpectralScanGroupLength(band,lo_freq,lo_freq_up,redundancy);

    return grouplen;
}

//Set LOU to diagnostic, block
block Set_LO_Diagnostic_block_fm HIFI 3664 {
}{
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_delays",["set_to_nominal_delay"],"0",0.0);
    int set_to_nominal_delay = iround(result[0]{0});
    //
    Hifi_HIFI_HL_Diagnostic($BBID);
    delay(set_to_nominal_delay);
    //
}

//////////////////////////////////////////////
/// Blocks
//////////////////////////////////////////////
//General LO configuration command
//  Uses SFT approach with old 5 TM TC call
block HIFI_Configure_LCU_block_sft HIFI 3977 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    int freq_nx = 0; // HL_freq_nx
    int lsu_main = 0; // HL_LSU_main
    int lsu_offset = 0; // HL_LSU_offset
    int d2_step = 1; // HL_D2_step
    double plevel_v = 0.0;
    double m1_v = 9.0;
    double m2_v = -2.0;
    double m3_v = 0.0;
    double gate1_v = -2.5;
    double gate2_v = -2.5;
    double drain1_v = 2.8;
    string curlim1_v = "1.4";
    double drain2_v = 2.6;
    string curlim2_v = "1.4";
    int macro_checksum = 0; // HL_macro_checksum
    int config_lo_delay = 6;
}{
    //Check that Vd2 is within the blue limits
    drain2_v = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v);
    //
    //Start_block(); 
    //
    //Execute configuration
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_safe_LCU_ch1a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_safe_LCU_ch1b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_safe_LCU_ch2a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_safe_LCU_ch2b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_safe_LCU_ch3a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_safe_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_safe_LCU_ch4a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_safe_LCU_ch4b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
    delay(config_lo_delay);
    //
    //Store settings into available register
    //HIFI_HL_store_tm_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_OLD_proc_fm();
}

// Functional test with unpumped mixer, procedure
// This case assumes no backend attenuator setting is done
procedure FT_unpumped {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,etc
    int integ_time = 4; //Integration time
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Fix for SPR-2520: init mixer band
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result_d[0];
    Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
    }
    //
    //(Re)configure spectrometers integration
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    //Measure IF noise
    IFcalibration(band,integ_time,backend);
    //IVcurve before and after magnet set to 0: not for band 6
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        //IV curve with default parameters
        IVcurve_raw_fm(band);
        //Set magnet to zero and get IVcurve: only up to band 5 since band6-7 have no magnets
        IVcurve_with_zero_magnet_fm(band);
        //Heater
        Heater_fm(band);
        //Now sets back the magnet to nominal value
        //Set magnet to zero and get IVcurve: only up to band 5 since band6-7 have no magnets
        IVcurve_with_zero_magnet_fm(band);
    }
    //IVcurve after defluxing
    IVcurve_defluxed_fm(band);
}

//HIFI-COP-2.3-Param-Scan: 1 per pair of scanned parameters
obs HifiEng_Parameter_Scan_COP {
    int index = 1 in [1,7]; // Test case index as of config_paramscan_COP.config
    int phase = 1 in [1,2]; //Measurement phase
    int m1_index = 1 in [1,5]; //Index of M1 value - only applicable is phase = 1. Index 1 is least negative
    int m2_index = 1 in [1,5]; //Index of M2 value - only applicable is phase = 1. Index 1 is least negative
    int bias_index = 1 in [1,3]; //Index of bias value - only applicable is phase = 2
    int imix_index = 1 in [1,3]; //Index of Imix value - only applicable is phase = 2
}{
    //Read corresponding band
    string tab = "config_paramscan_COP.config";
    string band = slookup(tab,"" + index,"band");
    //General parameters in use
    int integ_time = 4;
    //Integration time PER PHASE for the slowchop measurement  
    string[] hrs_mode = ["wb1","wb1"];
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Parameter_Scan_COP_proc_ops(index,phase,integ_time,hrs_mode,m1_index,m2_index,bias_index,imix_index));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Parameter_Scan_COP_proc_ops(index,phase,integ_time,hrs_mode,m1_index,m2_index,bias_index,imix_index);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// Step 1 of QLA_Testcontrol fine magnet-tuning loop
// Minimum IF power in the spectra
block Magnet_scan_fine_fm HIFI 3203 {
    string band = "1a";
    int integ_time = 4; //Integration time
    double lo_freq = 522.0; //LO frequency
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    Start_block();
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["magnet_current_min_h","magnet_current_max_h","magnet_current_min_v","magnet_current_max_v","jitter_margin","magnet_steps_h","magnet_steps_v"],band,0.0);
    //H polar
    double magnet_min_h = result_d[0]{0};
    double magnet_max_h = result_d[1]{0};
    //V polar
    double magnet_min_v = result_d[2]{0};
    double magnet_max_v = result_d[3]{0};
    //
    double magnet_min = max(magnet_min_h,magnet_min_h);
    double magnet_max = min(magnet_max_h,magnet_max_h);
    //
    int jitter_margin = iround(result_d[4]{0});
    int duration_scan = 0;
    double step_duration = double(2 + 2 * jitter_margin);
    int max_per_command = 40;
    int steps = 0;
    int steps_done = 0;
    //
    int steps_wanted_h = iround(result_d[5]{0});
    int steps_wanted_v = iround(result_d[6]{0});
    int steps_wanted = iround(max(double(steps_wanted_h),double(steps_wanted_v)));
    //  
    double step = Stepsize(magnet_min,magnet_max,steps_wanted,"hifi_HIF_mx_mg_step_C");
    double margin = Stepmargin(magnet_min,magnet_max,"hifi_HIF_mx_mg_step_C");
    steps_wanted = 1 + iceil((magnet_max - magnet_min) / step);
    // force the last portion to less than max_per_command
    if(max_per_command * (steps_wanted / max_per_command) == steps_wanted) {
        steps_wanted = steps_wanted - 1;
    }
    //
    //Set magnet to maximum to avoid hysteresis
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_max_v);
    delay(1);
    //
    double magnet_current_h = magnet_min_h;
    double magnet_current_v = magnet_min_v;
    //
    //We use special biasing to evidence the minima in the magnet scan
    result_d = ConfigurationReader("name_confilmix",["bias4magn_h","bias4magn_v"],band,lo_freq);
    double bias_h = result_d[0]{0};
    double bias_v = result_d[1]{0};
    //
    //Start scan: from max. to min. magnet downward.
    while(steps_done < steps_wanted) {
        steps = steps_wanted - steps_done;
        if(steps > max_per_command) {
            steps = max_per_command;
        }
        magnet_current_h = magnet_max_h - double(steps_done) * step;
        magnet_current_v = magnet_max_v - double(steps_done) * step;
        Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_current_h);
        Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_current_v);
        delay(1);
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
        steps_done = steps_done + 1;
    }
    //Back to nominal values
    //First set magnet to maximum to avoid hysteresis
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_max_v);
    delay(1);
    //Nominal values
    result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v","norm_bias_h","norm_bias_v"],band,lo_freq);
    magnet_current_h = result_d[0]{0};
    magnet_current_v = result_d[1]{0};
    bias_h = result_d[2]{0};
    bias_v = result_d[3]{0};
    Hifi_HIFI_FCU_parameter_scan($BBID,1,1,step_duration,bias_h,bias_v,0.0,magnet_current_h,magnet_current_v,0.0);
    delay(2);
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double} procedure FastDBSRaster_deadtimes {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval
    int n_int = 20; // number of integrations in one data dump interval
    int n_data = 3; // number of chop cycles in one integration
    int n_load = 0; // number of integrations in one pointing phase
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    double tdead = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Special meaning of n_load here
    if(n_load == 0) {
        int n_seq = 1;
    } else {
        n_seq = n_load;
    }
    // Compute parameters for the instrument timing
    {double,double} tinst = GetInstDeadFastChop(data_time,n_int,n_data,band,lo_freq,backendreadoutparms);
    // dead time
    double tdeadint = double(data_time * n_data) - tinst{0};
    // subtract dead times in switches
    // only half of them are subtracted due to ABAB scheme
    tdeadint = tdeadint - double(n_int * n_data) * tinst{1};
    // Total dead time per cycle, only one point still not covered
    double tdead_tot = tdead + double(2 * n_seq) * tdeadint;
    // Integration time
    double tphaseint = tinst{0} / double(2 * n_int * n_data);

    return {tdead_tot,tphaseint,tinst{1}};
}

// Compute Slow Chop delay necessary for integration, procedure
procedure Apply_Slow_Chop_delay {
    int total_time = 12; //single readout time * n_wbs_start
    string band = "1a"; // HIFI band
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Packet transfer time
    {double,string}[] result = ConfigurationReader("name_delays",["wbs_transfer_delay"],band,0.0);
    //
    int wbs_packet_transfer_time = iround(result[0]{0});
    //
    //In case less channels are used, one must adapt the transfer time
    if(backend == "hrs" || backend == "wbs") {
        //wbs_packet_transfer_time = 0;	//3000;
    }
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        //expect half backend
        //wbs_packet_transfer_time = 0;	//2000;
    }
    //
    //Compute delay
    int delay_slow_chop = total_time + wbs_packet_transfer_time / 1000;
    //debug_print("Slow Chop delay: " + delay_slow_chop + " sec");
    //
    //Apply delay
    delay(delay_slow_chop);
    //
}

//////////////////////////////////////////////////////////////////////
// Compatibility procedure to provide the same API as used in
// the previous versions
//
// Returns the actual integration time and the dead time per phase
{double,double} procedure ConfigSpectroscopySlowChop {
    /* Integration time */
    int data_time = 4; // Integration time between two data readouts
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string chopmode = "chop" in ["chop","lchop","fs","hot-cold","tp"]; // Chop mode determining the modulation dead time
    string band = "1a"; // HIFI band
    double lo_freq = 522000.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used,channel windows}
    bool docommands = false; // Whether instrument command is issued
}{
    // Get timing parameters
    {int,int,int,int,int,int,int,int,int,int} timing = ConfigureSpectroscopyParams(data_time,n_data,chopmode,band,lo_freq,backendreadoutparms);
    int n_wbs_start = timing{0};
    int r_hrs = timing{1};
    int n_wbs_integr = timing{2};
    int n_hrs_integr = timing{3};
    int del_hrs = timing{4};
    int del_wbs = timing{5};
    int t_acc_wbs = timing{6};
    int t_acc_hrs = timing{7};
    int tdead = timing{8};
    int tint_act = timing{9};
    // Transfer mode
    {int,int,int,int,int[],int[],string} backendconfigure = ConfigSpectroscopyBackends(data_time,backendreadoutparms);
    int wbs_rshift = backendconfigure{0};
    int hrs_rshift = backendconfigure{1};
    int hrsh_sel = backendconfigure{2};
    int hrsv_sel = backendconfigure{3};
    int[] wbsh_par = backendconfigure{4};
    int[] wbsv_par = backendconfigure{5};
    string packing = backendconfigure{6};
    // Now call the command
    if(docommands) {
        Hifi_HIFI_config_spectroscopy($BBID,n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,wbsh_par[0],wbsh_par[1],wbsh_par[2],wbsh_par[3],wbsh_par[4],wbsh_par[5],wbsh_par[6],wbsh_par[7],wbsv_par[0],wbsv_par[1],wbsv_par[2],wbsv_par[3],wbsv_par[4],wbsv_par[5],wbsv_par[6],wbsv_par[7],hrs_rshift,wbs_rshift,hrsh_sel,hrsv_sel,packing);
    }
    // Return actual integration time and dead time per readout

    return {double(tint_act) / 1000.0,double(tdead) / 1000.0};
}

//HIFI-COP-2.1-CPR-RespTime
procedure Chopper_Response_time_COP_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_comment("This test needs the successful execution and analysis of the full chopper health check suite");
    mois_comment("Start of HIFI Chopper response time test");
    mois_comment("Please check that instrument was switched on with the " + prime_or_redundant + " unit");
    //General parameters in use
    string band = "1a";
    // HIFI band
    double lo_freq = 520.0;
    //LO frequency
    string hbb_heater = "ON";
    //hot source on/off
    string chopper_loop = "CLOSE";
    int milliSecSample = 3;
    // interval between samples
    int samplesBefore = 30;
    int samplesAfter = 1000;
    //
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    //
    mois_step("Init FPU");
    Init_MSA_ops(band,chopper_loop,lo_freq,result[0]{0},hbb_heater,prime_or_redundant);
    mois_step("Rotate to hot internal load");
    //Rotate to HBB
    Chopper_Rotation_block_fm_COP(band,"chop_M3right_ang","chop_hot_ang",prime_or_redundant);
    mois_step("Response time sequence");
    //Chopper response time
    Chopper_Response_time_block_COP(band,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    //Fas
}

{int,double,double,double,double,double} procedure HifiIdealMode {
    string modeName = "pos";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // Get parameters which are needed
    double center_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    double tsys = InterpolateTsys(band,center_lo_freq);
    double eta_mb = InterpolateCoupling(band,center_lo_freq);
    double[] gssb = InterpolateGssb(band,center_lo_freq);
    double phasetime = double(goalTime);
    double noiseratio = 0.0;
    // Compute total double sideband noise 
    double dsbnoise_lores = tsys * sqrt(1.0 / (effResolution{1} * 1000000.0 * phasetime));
    double dsbnoise_hires = tsys * sqrt(1.0 / (effResolution{0} * 1000000.0 * phasetime));
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Get single sideband noise equivalent
    double usbnoise_lores = dsbnoise_lores / gssb[0];
    double usbnoise_hires = dsbnoise_hires / gssb[0];
    double lsbnoise_lores = dsbnoise_lores / gssb[1];
    double lsbnoise_hires = dsbnoise_hires / gssb[1];
    // return total time with initial slew
    int returntime = goalTime;
    // Originally I had added 180s from telescope
    // Now make corrections for maps or spectral scans
    if(npoints * nlines > 1) {
        double factor = sqrt(double(nlines * npoints));
        usbnoise_lores = usbnoise_lores * factor;
        usbnoise_hires = usbnoise_hires * factor;
        lsbnoise_lores = lsbnoise_lores * factor;
        lsbnoise_hires = lsbnoise_hires * factor;
    }
    if(lo_freq_up > lo_freq) {
        {int,double,double[],int[][],int,bool} fqparms = MakeFreqGrid(band,lo_freq,lo_freq_up,redundancy,0.0,1);
        factor = sqrt(double(fqparms{0} / fqparms{4}));
        usbnoise_lores = usbnoise_lores * factor;
        usbnoise_hires = usbnoise_hires * factor;
        lsbnoise_lores = lsbnoise_lores * factor;
        lsbnoise_hires = lsbnoise_hires * factor;
    }
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {returntime,usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiseratio};
}

// Routine to extract the settings for the two HK regimes
string[] procedure QueryHKPattern {
    bool active = false; // Whether to actively query the spectrometers
}{
    // HK pattern according to SRON-U/HIFI/SP/2001-001 4.3.2 PDU status
    if(active) {
        int pattern = ifloor(dlookup("datarates","allreadpattern","value"));
    } else {
        pattern = ifloor(dlookup("datarates","noreadpattern","value"));
    }
    // translate into new mask of arguments
    string[] mask = ["OFF","OFF","OFF","OFF","OFF","OFF"];
    for(int i = 0 .. 5) {
        if(pattern % 2 > 0) {
            mask[i] = "ON";
        } else {
            mask[i] = "OFF";
        }
        pattern = pattern / 2;
    }

    return mask;
}

/////////////////////////////////////////////////////////////////
// Slow chop dual beam switch observing mode - special version for Jupiter
// 
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiPointProcJupiterDBS {
    /* Setup parameters */
    int naifid = 0; // Tracing object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Engineering - Jupiter - DBS slowChop",{data_time,0,0,n_switch_on,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    // Two changes relative to the normal DBS 
    // 1) The longer load duration is enforced by zero resolution
    {double,double} loadResolution = {0.0,effResolution{1}};
    // 2) I assume that the tuning duration does not depend on the tuning level
    // so that the normal pre_timing can be reused.
    {int,int,int,int,int,int,int,int,int,bool,int,int,int} pre_timing = DBS_pre_timing(band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},bool,double,double} post_timing = DBS_post_timing(pre_timing,telescopetimes,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",post_timing{1},n_cycles);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_seq = post_timing{1}{8};
    int n_loadinterval = post_timing{1}{7};
    bool end_load = post_timing{1}{9};
    int shiftlength = post_timing{1}{10};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        JupiterDBS_commanding(band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,n_loadinterval,end_load,final_load,startobs,telescopetimes,loadlength,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = DBS_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBS_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,n_seq * (n_load + 1),tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//Set LOU to nominal, block
//no channel selected
block Set_LO_Nominal_block_ops HIFI 7626 {
}{
    //
    {double,string}[] result = ConfigurationReader("name_delays",["set_to_nominal_delay"],"0",0.0);
    int set_to_nominal_delay = iround(result[0]{0});
    //
    Hifi_HIFI_HL_Normal($BBID);
    delay(set_to_nominal_delay);
    //Will be done at end of procedure during instrument mode status check
    //mois_tmcheck("Check that parameter HL_MODE_S is normal");
    //
}

{string,double,double}[] procedure HifiMappingModeDBSRasterSequencerInit {
    string modeName = "raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // Get the drift parameters to compute the drift noise
    {double,double} phaselengths = DBSPhaseLengths(band,lo_freq,effResolution,continuumDetection,oneGHzReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // Combine points for n_switch=1
    int main_phase = iceil(phaselengths{0});
    int n_pointsperscan_guess = imin(imax(main_phase / (2 * data_time_guess),1),npoints * nlines);
    int n_pointsperscan_range = 1 - n_pointsperscan_guess;
    if(n_pointsperscan_range == 0) {
        n_pointsperscan_range = 1;
    }
    // remaining part for n_switch
    int n_switch_on_guess = main_phase / (n_pointsperscan_guess * 2 * data_time_guess) + 1;
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,2 * n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_pointsperscan",double(n_pointsperscan_guess),double(n_pointsperscan_range)}];

    return retvalues;
}

// Change LO frequency but keep backend configuration - used in spectral scans
//
// Currently, no adaption to a full HK reading is implemented here
procedure HIFIRetuneFsw {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency ion MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    string level = "sscan_normal"; // Name of target level
}{
    ConfigureFPU(band,lo_freq + freq_throw / 2.0,false);
    HIFITuneFreqFsw(band,lo_freq,lo_freq + freq_throw,true,level);
}

//  LCU switch-off, block
block LCU_switch_off_block_ops HIFI 7631 {
}{
    //
    {double,string}[] result = ConfigurationReader("name_delays",["switch_off_delay"],"0",0.0);
    int switch_off_delay = iround(result[0]{0});
    //
    //Send command: this is the effective switch-off
    Hifi_HIFI_Conf_nom_LCU_ch0($BBID);
    //Will be done at end of procedure during instrument mode status check
    //mois_tmcheck("Check that parameter HL_Channel_S is Off");
    delay(switch_off_delay);
    //
    //Set heater to their stby value: should not depend on band
    HL_heater_proc_ops("1a","stby");
}

//General script to clear error flags and set to nominal, block
block LCU_disable_all_bands_block_fm HIFI 3767 {
}{
    //
    //switch to standby
    {double,string}[] result = ConfigurationReader("name_delays",["stdby_delay"],"0",0.0);
    int stdby_delay = iround(result[0]{0});
    mois_comment("Set LOU to standby");
    Hifi_HIFI_HL_Standby($BBID);
    delay(stdby_delay);
    //Disable bands
    mois_comment("Disable all bands");
    mois_spacon("In the next TC, parameter HP443194 should be treated as FP");
    Hifi_HIFI_Conf_LCU_internal($BBID,0,"RESET","RESET",256);
    //sets bandmask to 3FFF: all bands
    //LSU_delta_f: 256 = 88mV
    //
}

//Check that drain2 is below blue max and above blue min
double procedure Check_BLUE_LIMIT_D2_proc_fm {
    string band = "4a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band   
    double lo_freq = 978.2; //LO Frequency
    double drain2_v = 1.4; //Current drain2 to compare to blue limits
}{
    //Check against blue max
    //Implementation of SCR-2220
    double drain2_max = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    double drain2_v_new = drain2_v;
    if(drain2_v > drain2_max) {
        drain2_v_new = drain2_max;
        //this already accounts for the margin
        message("Warning: drain2 (" + drain2_v + " V), was commanded above its blue max (" + drain2_max + " V).");
    }
    //Check against blue min
    //Implementation of SCR-2220
    double drain2_min = Get_BLUE_MIN_D2_proc_fm(band,lo_freq);
    //
    if(drain2_v < drain2_min) {
        drain2_v_new = drain2_min;
        message("Warning: drain2 (" + drain2_v + " V), was commanded below its blue min (" + drain2_min + " V).");
    }

    return drain2_v_new;
}

// Step 2 of QLA_Testcontrol coarse magnet-tuning loop
block Magnet_set_coarse_with_IVcurve_fm HIFI 3202 {
    string band = "1a";
}{
    Start_block();
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["bias_min_h","bias_max_h","bias_steps_h","bias_min_v","bias_max_v","bias_steps_v"],band,0.0);
    //H polar
    double bias_min_h = result_d[0]{0};
    double bias_max_h = result_d[1]{0};
    int steps_h = iround(result_d[2]{0});
    //V polar
    double bias_min_v = result_d[3]{0};
    double bias_max_v = result_d[4]{0};
    int steps_v = iround(result_d[5]{0});
    //Bias to set at end of IVC
    //Need a representative frequency: take keyfreq
    double[] result = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result[0];
    //
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v","norm_magn_h","norm_magn_v"],band,lo_freq);
    double bias_h = result_d[0]{0};
    double bias_v = result_d[1]{0};
    //Fetch magnets only if band is not band6
    double magnetcurrent_h = 0.0;
    double magnetcurrent_v = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        magnetcurrent_h = result_d[2]{0};
        magnetcurrent_v = result_d[3]{0};
    }
    //
    //The IVCurve is done on the smallest range and the finest step
    double bias_min = max(bias_min_h,bias_min_v);
    double bias_max = min(bias_max_h,bias_max_v);
    int steps = iround(max(double(steps_h),double(steps_v)));
    //
    //Set magnet to maximum to avoid hysteresis
    result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
    double magnet_current_max_h = result_d[0]{0};
    double magnet_current_max_v = result_d[1]{0};
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_current_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_current_max_v);
    delay(1);
    //Do IV curve
    IVcurve(band,bias_min,bias_max,steps,magnetcurrent_h,magnetcurrent_v,bias_h,bias_v);
}

////////////////////////////////////////
// Procedure to calculate the post timing
//
{int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},bool,double,double} procedure DBS_post_timing {
    {int,int,int,int,int,int,int,int,int,bool,int,int,int} pre_timing = {4,10,4,21,11,1800,0,32,1,false,0,50,0}; // pre_timing parameter list
    int[] telescopetimes = [300,180,20,1,21,0];
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF pointing cycles
}{
    // Get all values from the pre_timing section
    int inttime = pre_timing{0};
    int pointing = pre_timing{1};
    int readouttime = pre_timing{2};
    int loadlength = pre_timing{3};
    int jitterdead = pre_timing{4};
    int load_spacing = pre_timing{5};
    int n_load = pre_timing{6};
    int n_loadinterval = pre_timing{7};
    int n_seq = pre_timing{8};
    bool end_load = pre_timing{9};
    int shiftlength = pre_timing{10};
    int initlength = pre_timing{11};
    int dangling = pre_timing{12};
    // Get all values from the telescope section
    int telinit = telescopetimes[1];
    // Initial slew time
    int slewtime = telescopetimes[2];
    // Slew time to OFF
    int longslew = telescopetimes[4];
    // Actual slew time for load slew
    int pointwaittime = telescopetimes[3];
    // Idle time between two phases
    int tend = telescopetimes[5];
    // Final deceleration time
    //////////////////////////////////////////////////////////////////
    // Now we start the actual computations
    // Add pointwaittime to slew dead time in cycles
    slewtime = slewtime + pointwaittime;
    longslew = longslew + pointwaittime;
    // If load is performed between the cycles use pointwaittime for load
    if(end_load) {
        int halfloadlength = (loadlength - jitterdead + 1) / 2;
        int effhalfloadlength = (loadlength - jitterdead - pointwaittime + 1) / 2;
        int subtracted = halfloadlength - effhalfloadlength;
        pointing = pointing - subtracted;
        shiftlength = effhalfloadlength;
    }
    // Now we can compute the true scan time
    int scan_time = 2 * pointing + slewtime;
    // Finally I can compute the load interval
    n_loadinterval = imax((load_spacing + slewtime) / scan_time,1);
    // Compute duration of measurement and average scan length
    // Compute total dead time in one pointing cycle including load overhead
    int scan_time_long = 2 * pointing + longslew;
    int n_long = n_cycles / n_loadinterval;
    int looplength = (n_cycles - n_long) * scan_time + n_long * scan_time_long;
    double tscan = double(looplength) / double(n_cycles);
    // Get pointing dead time, instrument dead time is added later
    double tdead = tscan - double(2 * inttime);
    // Determine need for final load measurement
    double rest = double(n_cycles % n_loadinterval) + 0.5;
    bool final_load = rest > 0.5001 * double(n_loadinterval);
    // Compute total duration
    initlength = initlength - shiftlength;
    // The initial time is no longer contained in the total time
    // int totaltime=imax(initlength,telinit);
    int totaltime = looplength;
    // Add dangling load time, either of the two can apply, but
    // they are mutually exclusive, otherwise the readoutdelay applies
    if(final_load) {
        dangling = loadlength;
    }
    if(end_load) {
        dangling = loadlength - shiftlength;
    }
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    // Compute total duration, remove pointwaittime for last slew
    totaltime = totaltime + dangling - pointwaittime + tend;
    // show gyro-propagation messages
    GCPMessages(pointing,2 * scan_time_long,tend);
    // Return all the times needed in the observing mode modules
    // The second tuple contains the modified pre_timing parameters,
    // the rest the newly computed parameters

    return {totaltime,{inttime,pointing,readouttime,loadlength,jitterdead,load_spacing,n_load,n_loadinterval,n_seq,end_load,shiftlength,initlength,dangling},final_load,tscan,tdead};
}

/////////////////////////////////////////////////////////////////
// Spectral scan in load-chop with OFF calibration
// 
{string,double,double}[] procedure HifiSScanProcLoadChopSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half load-sky-sky-load cycles per frequency and pointing
    int n_switch_off = 1 in [1,900]; // number of half load-sky-sky-load cycles on OFF
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hr1{0},hr1{1},hr1{3}},{hr2{0},hr2{1},hr2{3}},wb1,wb2};
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    // Now general part of LoadChop modes
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {double,double,double,double} phaselengths = LoadChopPhaseLengths(band,lo_freq,effResolution,narrowReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // How much time for single ON phase
    int n_switch_on_guess = imax(iceil(2.0 * phaselengths{0} / ((double(n_freq_point_guess) + sqrt(double(n_freq_point_guess))) * 2.0 * double(data_time_guess))),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) * sqrt(double(n_freq_point_guess)) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)},{"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)}];

    return retvalues;
}

//General script to clear error flags and set to nominal, block
block LCU_disable_FreqTMY_check_block_fm HIFI 3667 {
}{
    //
    //Start_block();
    //switch to standby
    Hifi_HIFI_HL_Standby($BBID);
    {double,string}[] result = ConfigurationReader("name_delays",["stdby_delay"],"0",0.0);
    int stdby_delay = iround(result[0]{0});
    delay(stdby_delay);
    //Clear error flags
    Hifi_HIFI_Conf_LCU_internal($BBID,16383,"SET","RESET",256);
    //sets bandmask to 3FFF: all bands
    //LSU_delta_f: sets to 256 = 88mV
    //Switch back to nominal
    Hifi_HIFI_HL_Normal($BBID);
    int set_to_nominal_delay = stdby_delay;
    delay(set_to_nominal_delay);
    //
}

// WBS configuration with minimum attenuation, block
// Laser setup as in config file
block WBS_config_min_att_block_fm HIFI 3639 {
    string band = "1a"; // HIFI band
}{
    //Start_block();
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = result_d[0]{1};
    string hwh_laser2_s = result_d[1]{1};
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = 0;
    int hwh_att_band3 = 0;
    int hwh_att_band2 = 0;
    int hwh_att_band1 = 0;
    int hwh_att_in = 0;
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //delay(wbs_config_delay);
    //V-Polarization
    //Get configuration parameters
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = result_d[0]{1};
    string hwv_laser2_s = result_d[1]{1};
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = 0;
    int hwv_att_band3 = 0;
    int hwv_att_band2 = 0;
    int hwv_att_band1 = 0;
    int hwv_att_in = 0;
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    //Wait delay to allow all setting to be configured
    delay(wbs_config_delay);
}

// HRS partial configuration, block
// Configures the resolution mode
block HRS_config_resol_block_aot HIFI 6618 {
    string band = "4a"; // HIFI band
    string[] hrs_mode = ["wb","wb"]; //HRS resolution code
}{
    ////////////////////////////////////////////////////////////////////
    //Now Configure blocks
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_block_1","hrh_block_2","hrh_block_3","hrh_block_4","hrh_block_5","hrh_block_6","hrh_block_7","hrh_block_8"],band,0.0);
    string hrh_block_1 = result[0]{1};
    string hrh_block_2 = result[1]{1};
    string hrh_block_3 = result[2]{1};
    string hrh_block_4 = result[3]{1};
    string hrh_block_5 = result[4]{1};
    string hrh_block_6 = result[5]{1};
    string hrh_block_7 = result[6]{1};
    string hrh_block_8 = result[7]{1};
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrh_block_1,hrh_block_2,hrh_block_3,hrh_block_4,hrh_block_5,hrh_block_6,hrh_block_7,hrh_block_8);
    //delay(hrs_config_delay);
    //
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_block_1","hrv_block_2","hrv_block_3","hrv_block_4","hrv_block_5","hrv_block_6","hrv_block_7","hrv_block_8"],band,0.0);
    string hrv_block_1 = result[0]{1};
    string hrv_block_2 = result[1]{1};
    string hrv_block_3 = result[2]{1};
    string hrv_block_4 = result[3]{1};
    string hrv_block_5 = result[4]{1};
    string hrv_block_6 = result[5]{1};
    string hrv_block_7 = result[6]{1};
    string hrv_block_8 = result[7]{1};
    //
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrv_block_1,hrv_block_2,hrv_block_3,hrv_block_4,hrv_block_5,hrv_block_6,hrv_block_7,hrv_block_8);
    //
    //Wait delay to allow all setting to be configured
    delay(hrs_config_delay);
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of peakup mode
{int,int,int,int,int,double,int,int} procedure Peakup_pre_timing {
    int nlines_tot = 3 in [1,100]; // Number of rows in the map
    int npoints = 3 in [2,100]; // Number of points per row
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {false,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {false,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {false,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Fixed parameters for peak-up
    int data_time = 3;
    // Data dump period
    int n_chop = 1;
    // Number of chop cycles
    double eff_resolution = 1.6;
    // Reference resolution for load measurement
    int peakuptime = 3;
    // Time neede for peakup integration
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    // Compute parameters for the instrument timing
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    int inttime = 2 * n_chop * data_time;
    // integer integration time
    int pointing = inttime + peakuptime + jitterdead;
    // Pointing time
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution,data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Duration of initial set up
    int initlength = duration(HIFIInitObs());
    initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
    initlength = initlength + duration(HifiPeakupConfigure(data_time,n_chop,true,band,lo_freq,0.0,backendreadoutparms));
    // Add time for HK readout
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    initlength = initlength + hkduration;
    initlength = initlength + loadlength;
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed for telescope call and post_timing processing

    return {inttime,pointing,data_time,loadlength,n_chop,eff_resolution,initlength,dangling};
}

/////////////////////////////////////////////////////////////////////
// Procedure to generate the fine pointing telescope command for the 
// observing mode
{int,int,int,string,int,double,double,double,double,int} procedure Fine_telescope {
    int naifid = 0; // Tracking object ID
    {double,double} onposition = {0.0,0.0}; // Coordinates of the source
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {int,int,int,int,int,int,bool,int,int} timing = {16,16,21,1800,2,0,false,50,0}; // timing parameter list
}{
    // Assign values
    int on_pointing = timing{1};
    // Pointing time
    int initlength = timing{7};
    // Initial setup time
    int dangling = timing{8};
    // Final load measurement
    // Create variables for telescope command
    string ib = GetBoresight(band,lo_freq,false);
    // A change of ra-dec depending on naifid may be needed
    double ra = onposition{0};
    double dec = onposition{1};
    // Check parameter compatibility with pointing command for parameters
    // which are no direct input parameters
    if(on_pointing > 50000) {
        IError("Pointing too long. Break up the observation into smaller pieces.");
    }
    // return parameters in required order

    return {initlength,0,dangling,ib,naifid,ra,dec,0.0,0.0,on_pointing};
}

int block HIFI_DoubleCalibrate_hot_cold HIFI 6006 {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    int data_time = 4; // time between subsequent data readouts
    int n_data = 2; // Integration time counter
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
    bool staycal = false; // whether we should stay at the hot load at the end
}{
    // data rate and read-out time
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int readout = dataparms{0};
    // send the configure spectroscopy command to configure the measurement
    // returned dead times not needed here
    ConfigureSpectroscopy(data_time,n_data,"hot-cold",band,lo_freq,backendreadoutparms);
    // Switch to first FSW register
    Hifi_HIFI_HL_set_FSW1($BBID);
    // Spectroscopy should start at first bus slot
    delay(1);
    // Perform first slow-chop
    HIFI_Spectr_slow_chop_proc_aot(data_time,n_data / 2,band,lo_freq,["chop_hot","chop_cold"],dataparms{1});
    // Switch to second FSW register
    Hifi_HIFI_HL_set_FSW2($BBID);
    // delay required at the end
    int sdelay = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // Clean up for next spectroscopy
    delay(sdelay);
    // integrate
    HIFI_Spectr_slow_chop_proc_aot(data_time,n_data / 2,band,lo_freq,["chop_hot","chop_cold"],dataparms{1});
    if(!staycal) {
        // Switch to back FSW register
        Hifi_HIFI_HL_set_FSW1($BBID);
        // Move chopper back to the sky
        RotateChopper(band,lo_freq,"chop_M3");
    }
    // have clean bus timing for next spectroscopy block
    delay(sdelay);

    return readout;
}

//!!!!!!!!!!!!!!!!!!!!
// Associated blocks
//!!!!!!!!!!!!!!!!!!!!
// Procedure to compute the parameters needed in a Chopped HRS fast measurement
block Stability_chopped_fasthrs_block HIFI 3439 {
    /* Integration time */
    string band = "1a"; // HIFI band
    double lo_freq = 522.0; // LO frequency
    int data_time = 10; // Chop phase length
    int n_data = 10; // Number of phases
    double hrs_readout = 0.333; // HRS readout length
}{
    // Fixed backend configuration
    // No WBS
    int wbsh_offset1 = 0;
    int wbsh_width1 = 0;
    int wbsh_offset2 = 2048;
    int wbsh_width2 = 0;
    int wbsh_offset3 = 4096;
    int wbsh_width3 = 0;
    int wbsh_offset4 = 6144;
    int wbsh_width4 = 0;
    int wbsv_offset1 = 0;
    int wbsv_width1 = 0;
    int wbsv_offset2 = 2048;
    int wbsv_width2 = 0;
    int wbsv_offset3 = 4096;
    int wbsv_width3 = 0;
    int wbsv_offset4 = 6144;
    int wbsv_width4 = 0;
    string packing = "24_bits_format";
    // HRS
    int hrsh_sel = 128;
    //10000000 = 1U only
    int hrsv_sel = 128;
    //10000000 = 1U only
    // No bitshift
    int hrs_rshift = 0;
    int wbs_rshift = 0;
    // Timing - copied from ConfigSpectroscopyParams
    // Command jitter time is the default delay 
    {double,string}[] result = ConfigurationReader("name_delays",["add_jitter"],band,lo_freq);
    int add_jitter = iround(result[0]{0});
    // WBS delta time given by switch dead time
    double res = GetLoadChopDeadTime(band,lo_freq);
    // minimum delay
    int del_wbs = iceil(res * 1000.0);
    // HRS delta time - should be zero as well
    int del_hrs = add_jitter;
    // Additional delays in the readout loops - given in OBS user manual
    result = ConfigurationReader("name_delays",["add_hrs","add_wbs","add_jitter","wbs_init","wbs_chunksize","tacc_add","min_wbs_acc","scos_jitter"],band,lo_freq);
    int add_hrs = iround(result[0]{0});
    int add_wbs = iround(result[1]{0});
    int wbs_init = iround(result[3]{0}) + iround(result[7]{0});
    int wbs_chunksize = iround(result[4]{0});
    int tacc_add = iround(result[5]{0});
    int min_wbs_acc = iround(result[6]{0});
    // WBS transfer time
    // Split total integration time
    int tint = data_time * n_data * 1000;
    // dead time has to be an integer multiple of the 10ms chunk time
    int tdead = del_wbs + add_wbs + add_jitter;
    int nchunk = (tdead - 1) / wbs_chunksize + 1;
    int tcorr = nchunk * wbs_chunksize - tdead;
    del_wbs = del_wbs + tcorr;
    tdead = tdead + tcorr;
    // Accumulation time
    int t_acc_wbs = (tint - wbs_init) / n_data - tdead;
    // discretize in 10ms chunks
    nchunk = (t_acc_wbs - tacc_add) / wbs_chunksize;
    t_acc_wbs = nchunk * wbs_chunksize + tacc_add;
    // No WBS addition in ICU
    int n_wbs_integr = 1;
    int n_wbs_start = n_data;
    // HRS
    int hrs_phase = iceil(1000.0 * hrs_readout);
    int hrs_fullphase = hrs_phase + del_hrs + add_hrs;
    int r_hrs = (t_acc_wbs + hrs_fullphase - add_jitter) / hrs_fullphase;
    int t_acc_hrs = (t_acc_wbs - add_jitter) / r_hrs - del_hrs - add_hrs;
    // for n_wbs_integr=1 identical to r_hrs
    int n_hrs_integr = 1;
    // Issue configuration
    Hifi_HIFI_config_spectroscopy($BBID,n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,wbsh_offset1,wbsh_width1,wbsh_offset2,wbsh_width2,wbsh_offset3,wbsh_width3,wbsh_offset4,wbsh_width4,wbsv_offset1,wbsv_width1,wbsv_offset2,wbsv_width2,wbsv_offset3,wbsv_width3,wbsv_offset4,wbsv_width4,hrs_rshift,wbs_rshift,hrsh_sel,hrsv_sel,packing);
    //
    // Now call the spectroscopy
    //Get appropriate chopper voltages
    {bool,double,double} chopparms = GetChopVoltages(band,lo_freq,"chop_hot","chop_cold");
    bool isPrime = chopparms{0};
    // Call command
    if(isPrime) {
        Hifi_HIFI_P_Spectr_slow_chop($BBID,chopparms{1},chopparms{2});
    } else {
        Hifi_HIFI_R_Spectr_slow_chop($BBID,chopparms{1},chopparms{2});
    }
    delay(n_data * data_time + 3);
}

// Routines for calibration data handling
/////////////////////////////////////////////////////////////////
// Routines using the generic reader
// A possible frequency dependence is hidden behind the reader
/////////////////////////////////////////////////////////////////
// Interpolate gain in corresponding sideband for the selected frequency
double[] procedure InterpolateGssb {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] gssb = CalibrationReader("gain",["Gusb","Glsb"],band,lo_freq);

    return gssb;
}

//////////////////////////////////////////////////////////////////////////
// Procedure to generate the telescope command for the Peakup mode
{int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double} procedure Peakup_telescope {
    int naifid = 0; // Tracing object ID
    {double,double} mapcenter = {0.0,0.0}; // Coordinates of the center of the map
    double stepsize = 0.0050; // Distance between subsequent points in the raster line
    int nlines = 1; // Number of rows in the map;
    int npoints = 10; // Number of points per row 
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {int,int,int,int,int,double,int,int} timing = {8,10,2,21,4,1.6,50,0}; // timing parameter list  
}{
    // Assign values
    int pointing = timing{1};
    int initlength = timing{6};
    int dangling = timing{7};
    // Create variables for telescope command
    string ib = GetBoresight(band,lo_freq,false);
    // A change of ra-dec depending on naifid may be needed
    double ra = mapcenter{0};
    double dec = mapcenter{1};
    // Map always in spacecraft coordinates, always start in +Z direction
    bool fixed = false;
    double patt = 0.0;
    // Map parameters
    double rowstep = 0.5 / 3600.0;
    double d1 = double(iceil(stepsize / rowstep)) * rowstep * 3600.0;
    // Exception for the "impossible" case of spacings below 2arcsec
    d1 = max(d1,2.0);
    // Always isotropic for peakup
    double d2 = d1;
    // Check parameter compatibility with pointing command for parameters
    // which are no direct input parameters
    if(pointing < 10) {
        SError("Pointing phase length too short. Increase the number of integrations.");
    }
    if(d1 > 480.0) {
        IError("Raster spacing too coarse. Increase the sampling.");
    }
    // parameters for OFF position - not used
    int koff = 0;
    int toff = 0;
    double raoff = 0.0;
    double decoff = 0.0;
    // return parameters in required order

    return {initlength,0,dangling,ib,naifid,ra,dec,fixed,patt,0.0,0.0,npoints,nlines,d1,d2,pointing,koff,toff,raoff,decoff};
}

//TM to control FDIR on LOU temp
block Set_LO_FDIR_temperatures_block_mois HIFI 3853 {
}{
    // BBID needs to be set manually as the main TC command has no BBID argument
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    delay(1);
    //Fetch values to apply: band-independent so far
    double[] cresult = CalibrationReader("name_loheater",["tmin","tmax","nbreach"],"1a",0.0);
    double tmin = cresult[0];
    //Min threshold
    double tmax = cresult[1];
    //Max threshold
    int nbreach = iround(cresult[2]);
    //Number of breach
    //
    mois_spacon("In the next TC, the parameters HP460197 and HP461197 should be treated as FP");
    Hifi_HIFI_LOU_T_check_on(nbreach,tmax,tmin);
    delay(1);
    //
}

// Configuration for continuous integration
block HIFIConfigureContIntegration HIFI 6020 {
    int data_time = 4; // Integration time between two data readouts
    int n_int = 1; // Integration time counter
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used, channel windows}
}{
    // Call procedure doing the work
    ConfigureSpectroscopy(data_time,n_int,"tp",band,lo_freq,backendreadoutparms);
}

//HIFI measurement of HEB spectra variation vs Imix, procedure
//Takes spectra over the full Vd2 range
procedure Vector_scan_BLUE_LIMIT_w_spectra_proc_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    int intermediatetime = 900; //total time remaining to scan
}{
    //Configure Spectro in total power
    int[] res = [0,0];
    string[] hrs_mode = ["wb1","wb1"];
    int total_time = 4;
    string backend = "both";
    res = Configure_Spectrometer_proc_fm(band,total_time,hrs_mode,backend);
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    drain2_v_start = drain2_safe;
    //Take lowest value from config_HEB_Imix_spec.config
    string tabimix = "config_HEB_Imix_spec.config";
    double bandnb = GetBandCode(band);
    drain2_v_start = dlookup(tabimix,"" + iceil(bandnb),"vd2min");
    drain2_v_start = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v_start);
    //
    double drain2_max = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //Take highest value from config_HEB_Imix_spec.config
    drain2_max = dlookup(tabimix,"" + iceil(bandnb),"vd2max");
    //Clip to blue max
    drain2_max = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_max);
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //First step at max Vd2
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lodelay = iround(result[0]{0});
    int config_lo_delay = config_lodelay;
    //
    int starttime = time();
    //First setting at max Vd2
    double drain2_v_current = drain2_max;
    HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_current,curlim2,macro_checksum,config_lo_delay);
    //
    //Take spectrum
    Spectro_total_power_block_fm(band,res,backend);
    int iterationtime = time() - starttime - 2;
    //remove 2 as further configlodelay are 2sec shorter
    //Clear flag in case we have entered failure mode in the first setting
    Set_LO_Nominal_proc_fm();
    //From now on it's alea jacta est
    //Scan is performed from top to bottom
    //We compute the nb of step based on the time needed for one iteration
    int nbstep = intermediatetime / iterationtime;
    //Compute step size
    double step_drain2_v = -1.0 * (drain2_max - drain2_v_start) / double(nbstep - 1);
    //
    //debug_print(nbstep);
    //debug_print(step_drain2_v);
    //Increment step
    drain2_v_current = drain2_v_current + step_drain2_v;
    //If not the first setting, the configuration time should be smaller
    //as we don't change the frequency
    config_lo_delay = config_lodelay - 2;
    //Start loop on further settings
    for(int i = 1 .. nbstep - 1) {
        //    while (drain2_v_current >= drain2_v_start) {
        //Configure Vd2
        HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_current,curlim2,macro_checksum,config_lo_delay);
        //
        //Take spectrum
        Spectro_total_power_block_fm(band,res,backend);
        //Increment step
        drain2_v_current = drain2_v_current + step_drain2_v;
        if(drain2_v_current < drain2_v_start) {
            drain2_v_current = drain2_v_start;
        }
    }
}

//////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the observing mode
{double,double,double,double,double} procedure FSwitchNoRef_noisecomputer {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    int n_cycles = 1; // Number of map coverages
    double tscan = 60.0; // Total average duration of one scan
    double tdead = 10.0; // Average dead time in one slew
}{
    // Call position switch noise computer
    {double,double,double,double,double} noisevalues = PositionSwitch_noisecomputer(band,lo_freq,eff_resolution,oneGHzReference,n_cycles,tscan,tdead);
    // Correct for signal in both phases
    double multiplier = sqrt(0.5);
    noisevalues{0} = noisevalues{0} * multiplier;
    noisevalues{1} = noisevalues{1} * multiplier;
    noisevalues{2} = noisevalues{2} * multiplier;
    noisevalues{3} = noisevalues{3} * multiplier;
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Switch HIFI on, block
//
block HIFI_global_switch_on_block_ops HIFI 7925 {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    StartBlock_ops();
    //Sequentially switches on, then notify PDU
    //
    //WBS-H
    mois_step("Switch ON WBS-H S/S");
    PDU_switch_on_proc_ops("WBS_H");
    mois_comment("Notify PDU status for WBS-H");
    HIFI_notify_PDU_status_on_proc_ops("ON","OFF","OFF","ON","OFF","OFF","WBSH");
    //WBS-V
    mois_step("Switch ON WBS-V S/S");
    PDU_switch_on_proc_ops("WBS_V");
    mois_comment("Notify PDU status for WBS-H");
    HIFI_notify_PDU_status_on_proc_ops("ON","OFF","ON","ON","OFF","OFF","WBSV");
    //HRS-H and HRS-V are first powered ON, FT#0 is done, then notify PDU
    mois_step("Switch ON HRS-H S/S");
    PDU_switch_on_proc_ops("HRS_H");
    mois_step("Switch ON HRS-V S/S");
    PDU_switch_on_proc_ops("HRS_V");
    //HRS FT#0 and special HK handling for this
    mois_step("HRS start-up");
    mois_comment("House-keeping for HRS-H and HRS-V is de-selected");
    Switch_HK_proc_ops("ON","ON","ON","ON","OFF","OFF");
    mois_comment("Notify PDU status for HRS-H and HRS-V");
    HIFI_notify_PDU_status_on_proc_ops("ON","OFF","ON","ON","OFF","ON","HRSH");
    HIFI_notify_PDU_status_on_proc_ops("ON","OFF","ON","ON","ON","ON","HRSV");
    HRS_functional_test_No_0_proc_ops();
    mois_comment("House-keeping for HRS-H and HRS-V is selected again");
    Switch_HK_proc_ops("ON","ON","ON","ON","ON","ON");
    mois_comment("Initial configuration of HRS blocks and LO");
    HRS_standby_proc_ops("0",["wb","wb"]);
    //LOU
    mois_step("Switch ON LO S/S");
    string lo_subsys = "LO_Prime";
    if(prime_or_redundant == "Red") {
        lo_subsys = "LO_Red";
    }
    PDU_switch_on_proc_ops(lo_subsys);
    mois_comment("Notify PDU status for LCU");
    HIFI_notify_PDU_status_on_proc_ops("ON","ON","ON","ON","ON","ON","LCU");
}

{string,double,double}[] procedure HifiMappingModeFSwitchOTFSequencerInit {
    string modeName = "fs-raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    {double,double,double,double} phaselengths = FSwitchPhaseLengths(band,lo_freq,effResolution,oneGHzReference);
    // Compute derived quantities
    // Main loop
    int main_phase = iceil(phaselengths{0});
    // How many lines could we do at most?
    int n_linesperscan_guess = main_phase / (2 * datalimit) + 1;
    n_linesperscan_guess = imax(n_linesperscan_guess * n_linesperscan_guess / npoints,1);
    // restrict the scan size
    if(nlines == 1 && n_linesperscan_guess > 1) {
        n_linesperscan_guess = 2;
    } else {
        n_linesperscan_guess = IMultiple(n_linesperscan_guess,nlines);
        n_linesperscan_guess = imin(n_linesperscan_guess,nlines);
    }
    int n_linesperscan_range = 1 - n_linesperscan_guess;
    if(n_linesperscan_range == 0) {
        n_linesperscan_range = 1;
    }
    double n_pointsperscan = double(n_linesperscan * npoints);
    // Compute back
    int int_time_guess = main_phase / iceil(sqrt(n_pointsperscan));
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int n_switch_on_guess = imax(int_time_guess / (2 * data_time_guess),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    data_time_guess = imax(imin(5,int_time_guess / (2 * n_switch_on_guess)),datalimit);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) * 0.67 * sqrt(n_pointsperscan) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)},{"n_linesperscan",double(n_linesperscan_guess),double(n_linesperscan_range)}];

    return retvalues;
}

//HIFI-COP-2.1-Stab-IF
obs HifiEng_stability_IF_system_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //General parameters in use
    int n = 751;
    //Number of load pairs to be measured
    string mixer_polarization = "B";
    //Polarization: H, V, or both (B) 
    int integ_time = 4;
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //Use high biases
    {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_high_resistive_h"],band,0.0);
    //
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Proc_stability_IF_system(band,n,hrs_mode,mixer_polarization,integ_time,backend,result[0]{0}));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Proc_stability_IF_system(band,n,hrs_mode,mixer_polarization,integ_time,backend,result[0]{0});
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//HIFI-COP-1.2-HRS_FT
procedure HRS_FT_COP_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_comment("Start of HIFI HRS Functional Test");
    //General parameters in use: use band 5
    string band = "5a";
    double lo_freq = 1122.0;
    int integ_time = 4;
    string backend = "hrs";
    string[] hrs_mode = ["wb1","wb1"];
    string laser_H = "Laser2";
    string laser_V = "Laser2";
    //
    string hbb_heater = "ON";
    //hot source on/off
    string chopper_loop = "CLOSE";
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    mois_step("Switch FPU band 5");
    double chopper_voltage = result[0]{0};
    Init_MSA_ops(band,chopper_loop,lo_freq,chopper_voltage,hbb_heater,prime_or_redundant);
    mois_tmcheck("Check that parameter HF_DH1_MXBAND and HF_DV1_MXBAND are both 5");
    //Set mixer bias to 5mV
    mois_step("Turn on shot noise for band 5 mixers");
    result = ConfigurationReader("name_confilfpu",["bias_low_resistive_h","bias_low_resistive_v"],band,0.0);
    double bias_low_h = result[0]{0};
    double bias_low_v = result[1]{0};
    //Set magnets to 0
    Set_Magnet_current_block_fm(0.0,0.0);
    mois_tmcheck("Check that parameters HF_AH1_MXMG_C and HF_AV1_MXMG_C are both set to 0 mA");
    //
    Mixerbias(bias_low_h,bias_low_v);
    mois_tmcheck("Check that parameters HF_AH1_MXBIAS_V and HF_AV1_MXBIAS_V are set to " + bias_low_h + " and " + bias_low_v + " mV respectively");
    //
    mois_step("HRS FT#1");
    HRS_functional_test_No_1_block_fm();
    //
    mois_step("HRS to standby and tuning");
    HRS_config_max_att_block_fm(band,hrs_mode);
    HRS_tune_block_fm(band);
    //To check final attenuator settings
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
    //
    mois_step("HRS FT#2 with square_s");
    HRS_functional_test_No_2_Square_s_block_fm(band,hrs_mode,integ_time,backend);
    //
    mois_step("HRS FT#2 with square_m");
    HRS_functional_test_No_2_Square_m_block_fm(band,hrs_mode,integ_time,backend);
    //
    mois_step("HRS FT#2 with sine");
    HRS_functional_test_No_2_Sine_block_fm(band,hrs_mode,integ_time,backend);
    //
    mois_step("HRS FT#2 with correlation");
    HRS_config_att_lo_block_fm(band,hrs_mode);
    HRS_tune_block_fm(band);
    HRS_functional_test_No_2_Corr_block_fm(band,hrs_mode,integ_time,backend);
    //
    mois_step("HRS FT#4");
    HRS_functional_test_No_4_block_fm(band,hrs_mode,integ_time,backend);
    //
    mois_step("HRS linearity test");
    HRS_linearity_indiv_block_cop(band,hrs_mode,integ_time,"hrs");
    //
    mois_step("HRS cross-polar");
    HRS_polar_switch_proc_fm(band,hrs_mode);
    //
    mois_step("HRS tuning");
    HRS_tune_block_fm(band);
    //To check final attenuator settings
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
    //
    mois_step("Switch to FPU band 0");
    Init_MSA_ops("0",chopper_loop,lo_freq,chopper_voltage,hbb_heater,prime_or_redundant);
}

/////////////////////////////////////////////////////////////////
// Spectral scan in frequency switch with OFF calibration
// 
{string,double,double}[] procedure HifiSScanProcFSwitchSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_switch_off = 1 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hr1{0},hr1{1},hr1{3}},{hr2{0},hr2{1},hr2{3}},wb1,wb2};
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    // Now general part of Frequency switch modes
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {double,double,double,double} phaselengths = FSwitchPhaseLengths(band,lo_freq,effResolution,narrowReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // How much time for single ON phase
    int n_switch_on_guess = imax(iceil(2.0 * phaselengths{0} / ((double(n_freq_point_guess) + sqrt(double(n_freq_point_guess))) * 2.0 * double(data_time_guess))),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) * sqrt(double(n_freq_point_guess)) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)},{"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)}];

    return retvalues;
}

{int,double,double,double,double,double} obs HifiMappingModeFastDBSCross {
    string modeName = "cross";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Mapping - DBS Cross Map fastChop",{data_time,0,n_switch_on,n_int_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = FastDBSRaster_pre_timing(2,npoints,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,double[],double[],int[],double,double,int,int,int,int,int,int} tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = custom_map_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSCross_post_timing(pre_timing,telescopetimes,npoints,n_switch_on,n_cycles,load_interval,true);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",post_timing{1},n_cycles);
    telescopetimes = custom_map_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int scansize = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FastDBSRaster_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,true);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastDBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,2,npoints,n_cycles,n_seq * n_int_on * imax(n_load,1),tact);
    // Correct for double counting of central point
    // The central point is returned only
    double multiplier = sqrt(0.5);
    noisevalues{0} = noisevalues{0} * multiplier;
    noisevalues{1} = noisevalues{1} * multiplier;
    noisevalues{2} = noisevalues{2} * multiplier;
    noisevalues{3} = noisevalues{3} * multiplier;
    noisevalues{4} = noisevalues{4} / multiplier;
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//Generic procedure for slowchop using the adequate instrument side
//It also converts prime voltage into redundant voltage
procedure HIFI_Spectr_fast_chop_proc_fm {
    double chop_angle1 = 0.0;
    double chop_angle2 = 0.0;
    int n_wbs1 = 1;
    int n_hrs_trans = 1;
}{
    //Convert prime voltage into redundant voltage
    chop_angle1 = Check_Chopper_Prime_Redundant(chop_angle1);
    chop_angle2 = Check_Chopper_Prime_Redundant(chop_angle2);
    //check prime or redundant keyword
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant"],"0",0.0);
    if(result_d[0]{1} == "prime") {
        Hifi_HIFI_P_Spectr_fast_chop($BBID,chop_angle1,chop_angle2,n_wbs1,n_hrs_trans);
    } else {
        Hifi_HIFI_R_Spectr_fast_chop($BBID,chop_angle1,chop_angle2,n_wbs1,n_hrs_trans);
    }
    //
}

//HIFI-COP-X-Dip-FSW
obs HifiEng_Dip_FSW_COP {
    string band = "3a" in ["3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI band
    string polarization = "H" in ["H","V"]; //The polarization on which the test is done
    int nb_pairs = 20; //number of FSW1-FSW2 pairs
    int throw_index = 1; //index of FSW throw as of stab FSW table of throws
    int freq_index = 1; //index of FSW throw as of stab FSW table of frequencies
    bool retune = true; //whether the diplexer is adjusted between frequencies or not
}{
    //General parameters in use
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    int integ_time = 4;
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Dip_FSW_COP_proc_ops(band,throw_index,freq_index,hrs_mode,integ_time,backend,nb_pairs,polarization,retune));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Dip_FSW_COP_proc_ops(band,throw_index,freq_index,hrs_mode,integ_time,backend,nb_pairs,polarization,retune);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//HRS Functional Test #0, block: right after switch on, BEFORE HK collection
block HRS_functional_test_No_0_block_ops HIFI 7610 {
}{
    mois_comment("Performing HRS Functional Test #0");
    //Use new command implemented in SCR-859
    Hifi_HIFI_HRS_functional_test($BBID,0,"BOTH");
    delay(5);
    //
}

// Take freq switch spectra, block
block Spectro_freq_switch_block_fm HIFI 3612 {
    string band = "1a"; // HIFI band
    int[] timing_parms = [4,2]; //single readout time in sec. and n_wbs_start
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //Compute data-rate
    int integ_time = timing_parms[0] * timing_parms[1];
    double[] rates = ILT_datarate_proc_fm(band,backend,"fsw",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    Hifi_HIFI_Spectr_freq_switch($BBID);
    Apply_Slow_Chop_delay(integ_time,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure PositionSwitch_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int n_cycles = 1; // Number of map coverages
    double tscan = 60.0; // Total average duration of one scan
    double tdead = 10.0; // Average dead time in one slew
}{
    double inttime = (tscan - tdead) / 2.0;
    // Integration time per pointing phase
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    double idealnoise = idealvalues{1} * idealvalues{1};
    double obsnoise = noisevalues{0} * noisevalues{0};
    double efficiency = idealnoise / obsnoise;
    // Compute integration time
    double posinttime = inttime * double(n_cycles);
    double timeefficiency = 2.0 * posinttime / double(totaltime);
    // Drift noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posinttime,timeefficiency,efficiency,relnoise,false);
}

//HIFI-COP-3-Deflux
//Systematic deflux at beginning of each OD, or band switch
procedure Deflux_COP_proc_ops {
    string band = "1a" in ["ALL","1a","1b","2a","2b","3a","3b","4a","4b"]; // HIFI band. ALL does all mixer bands
}{
    if(band != "ALL") {
        Deflux_SingleBand_proc_ops(band);
    } else {
        Deflux_SingleBand_proc_ops("1a");
        Deflux_SingleBand_proc_ops("2a");
        Deflux_SingleBand_proc_ops("3a");
        Deflux_SingleBand_proc_ops("4a");
    }
}

/////////////////////////////////////////////////////////////////
// Spectral scan in load-chop without OFF calibration
// 
{string,double,double}[] procedure HifiSScanProcLoadChopNoRefSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_cycles = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    // inherit from fs-noref mode
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {string,double,double}[] retvalues = HifiPointProcLoadChopNoRefSequencerInit(naifid,ra,dec,band,reffreq,effResolution,narrowReference,hr1,hr2,wb1,wb2,data_time,n_cycles,load_interval,docommands);
    retvalues[1] = {"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)};

    return retvalues;
}

//HIFI-COP-1.2-WBS_FT
procedure WBS_FT_COP_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_comment("Start of HIFI WBS Functional Test");
    //General parameters in use
    string band = "0";
    int integ_time = 4;
    string backend = "wbs";
    double lo_freq = 500.0;
    //0. Ensure band0: no IF input power
    string hbb_heater = "ON";
    //hot source on/off
    string chopper_loop = "CLOSE";
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    mois_step("FPU set to band0");
    Init_MSA_ops(band,chopper_loop,lo_freq,result[0]{0},hbb_heater,prime_or_redundant);
    mois_tmcheck("Check that parameter HF_DH1_MXBAND and HF_DV1_MXBAND are both 0");
    //
    string laser_H = "Lasers_off";
    string laser_V = "Lasers_off";
    //
    //1. Zero w/o laser
    mois_step("WBS Zero without Laser");
    WBS_config_w_laser_block_fm(band,laser_H,laser_V);
    mois_tmcheck("Check that parameters HWH_Laser1_S, HWH_Laser2_S, HWV_Laser1_S and HWV_Laser2_S are all OFF");
    WBS0_fm(band);
    WBS0_fm(band);
    //2. WBS FT
    //Configure WBS laser according to user inputs.
    laser_H = "Laser1";
    laser_V = "Laser1";
    mois_step("Configure WBS with Laser 1");
    WBS_config_w_laser_block_fm(band,laser_H,laser_V);
    mois_tmcheck("Check that parameters HWH_Laser1_S and HWV_Laser1_S are ON");
    //Wait 2 minutes for laser stabilization
    mois_comment("wait 2 minutes for stabilization");
    delay(120);
    //Do zero
    mois_step("WBS Zero with Laser 1");
    WBS0_fm(band);
    //Do zero and COMB
    mois_step("WBS Comb with Laser 1");
    WBS_calib_fm(band);
    // Configure spectroscopy
    mois_step("Attenuator scans with Laser 1");
    Configure_Spectrometer_proc_fm(band,integ_time,["wb1","wb1"],backend);
    //Set att. to min. and take spectrum
    WBS_config_min_att_w_laser_block_fm(band,laser_H,laser_V);
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
    //Scan all attenuators to get attenuator steps
    FT_WBS_att_overall_fm(band,integ_time,laser_H,laser_V,backend);
    FT_WBS_att_individual_fm(band,integ_time,laser_H,laser_V,backend);
    //3. Linearity test
    mois_step("WBS linearity test with Laser 1");
    FT_WBS_linearity(band,integ_time,laser_H,laser_V,backend);
    //4. Lacthup test
    mois_step("WBS latchup test with Laser 1");
    WBS_set_Latchup_block_fm(band,"high",laser_H,laser_V);
    mois_tmcheck("Check that parameters HWH_LUP_level_S and HWV_LUP_level_S are both High");
    WBS_set_Latchup_block_fm(band,"low",laser_H,laser_V);
    mois_tmcheck("Check that parameters HWH_LUP_level_S and HWV_LUP_level_S are both Low");
    //5. Tuning
    mois_step("WBS tuning with Laser 1");
    band = "5a";
    lo_freq = 1122.0;
    Init_MSA_ops(band,chopper_loop,lo_freq,result[0]{0},hbb_heater,prime_or_redundant);
    mois_tmcheck("Check that parameter HF_DH1_MXBAND and HF_DV1_MXBAND are both 5");
    WBS_tune_proc_fm(band);
    //To check final attenuator settings
    Configure_Spectrometer_proc_fm(band,integ_time,["wb1","wb1"],backend);
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
    //
    //Repeat with laser 2
    laser_H = "Laser2";
    laser_V = "Laser2";
    //
    //
    mois_step("FPU set to band0");
    band = "0";
    lo_freq = 500.0;
    Init_MSA_ops(band,chopper_loop,lo_freq,result[0]{0},hbb_heater,prime_or_redundant);
    mois_tmcheck("Check that parameter HF_DH1_MXBAND and HF_DV1_MXBAND are both 0");
    //2. WBS FT
    //Configure WBS laser according to user inputs.
    mois_step("Configure WBS with Laser 2");
    WBS_config_w_laser_block_fm(band,laser_H,laser_V);
    mois_tmcheck("Check that parameters HWH_Laser2_S and HWV_Laser2_S are ON");
    //Wait 2 minutes for laser stabilization
    mois_comment("wait 2 minutes for stabilization");
    delay(120);
    //Do zero
    mois_step("WBS Zero with Laser 2");
    WBS0_fm(band);
    //Do zero and COMB
    mois_step("WBS Comb with Laser 2");
    WBS_calib_fm(band);
    // Configure spectroscopy
    mois_step("Attenuator scans with Laser 2");
    Configure_Spectrometer_proc_fm(band,integ_time,["wb1","wb1"],backend);
    //Set att. to min. and take spectrum
    WBS_config_min_att_w_laser_block_fm(band,laser_H,laser_V);
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
    //Scan all attenuators to get attenuator steps
    FT_WBS_att_overall_fm(band,integ_time,laser_H,laser_V,backend);
    FT_WBS_att_individual_fm(band,integ_time,laser_H,laser_V,backend);
    //3. Linearity test
    mois_step("WBS linearity test with Laser 2");
    FT_WBS_linearity(band,integ_time,laser_H,laser_V,backend);
    //4. Lacthup test
    mois_step("WBS latchup test with Laser 2");
    WBS_set_Latchup_block_fm(band,"high",laser_H,laser_V);
    mois_tmcheck("Check that parameters HWH_LUP_level_S and HWV_LUP_level_S are both High");
    WBS_set_Latchup_block_fm(band,"low",laser_H,laser_V);
    mois_tmcheck("Check that parameters HWH_LUP_level_S and HWV_LUP_level_S are both Low");
    //5. Tuning
    mois_step("WBS tuning with Laser 2");
    band = "5a";
    lo_freq = 1122.0;
    Init_MSA_ops(band,chopper_loop,lo_freq,result[0]{0},hbb_heater,prime_or_redundant);
    mois_tmcheck("Check that parameter HF_DH1_MXBAND and HF_DV1_MXBAND are both 5");
    WBS_tune_proc_fm(band);
    //To check final attenuator settings
    Configure_Spectrometer_proc_fm(band,integ_time,["wb1","wb1"],backend);
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
    //
}

// Routine to compute the periodic HK parameters
{string,int,double,double,double,double} procedure PeriodicHKParms {
    string speed = "normal" in ["fast","normal","slow"]; // Select HK rate
}{
    // HK rate value accoring to IFSI/OBS/MA/2005-001
    int ratevalue = ifloor(dlookup("datarates",speed + "_hkrate_value","value"));
    // Assign
    // No exception handling here - CUS internals only
    string[] allowedvalues = ["1_pkt_per_5_s","1_pkt_per_10_s","1_pkt_per_s","1_pkt_per_3_s","1_pkt_per_4_s"];
    int[] allowedperiods = [5,10,1,3,4];
    string hk_string = allowedvalues[ratevalue];
    int hk_period = allowedperiods[ratevalue];
    // Get all relevant parameters
    int pmax = ifloor(dlookup("datarates","maxbuspackets","value"));
    int per_hkpackets = iceil(dlookup("datarates","periodic_hkpackets","value"));
    int per_hksize = iceil(dlookup("datarates","periodic_hksize","value"));
    int ess_hkpackets = iceil(dlookup("datarates","ess_hkpackets","value"));
    int ess_hksize = iceil(dlookup("datarates","ess_hksize","value"));
    int osize = ifloor(dlookup("datarates","packetoverhead","value"));
    // Compute rates
    double per_packetrate = double(per_hkpackets) / double(hk_period);
    double per_datarate = double(per_hkpackets * (per_hksize + osize)) / double(hk_period);
    double ess_packetrate = double(ess_hkpackets) / double(hk_period);
    double ess_datarate = double(ess_hkpackets * (ess_hksize + osize)) / double(hk_period);
    // return everything

    return {hk_string,hk_period,per_packetrate,per_datarate,ess_packetrate,ess_datarate};
}

procedure SError {
    string errormessage = "Bad sequence parameters."; // Error message
}{
    string fullmessage = "Invalid sequence parameter combination:<br>" + errormessage + "<br>Rerun the sequencer to obtain a valid observing request.";
    error(fullmessage);
}

// Broadcast OBSID
block BroadcastOBSID HIFI 900 {
}{
    //These are ILT-EGSE commands, not ruled by the 2TC/sec.
    //HifiIltEgse_PDU_set_OBS_ID($OBSID);
    //HifiIltEgse_PDU_set_BB_ID($BBID);
    //delay(1);
    //HifiIltEgse_FPU_set_OBS_ID($OBSID);
    //HifiIltEgse_FPU_set_BB_ID($BBID);
    //delay(1);
    //SpireIltEgse_QCC_SETOBSID($OBSID);
    //SpireIltEgse_QCC_SETBBID($BBID);
    //delay(1);
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    Hifi_HIFI_non_periodic_hk_FCU();
    delay(1);
}

// Get maximum delay needed for backend readout after SlowChopSpectroscopy
int procedure SlowChopReadoutDelay {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used, channel windows}
}{
    // Currently the delay applies independent from the spectrometer selection
    // if (backendreadoutparms{2}{0} || backendreadoutparms{3}{0}) {
    double[] dead = CalibrationReader("slowchopreadout",["slowchopreadout"],band,lo_freq);
    // }

    return iceil(dead[0]);
}

//LCU IV curves, block
//The LO needs to be switched off prior to the IV curve
block Measure_LCU_IV_block_fm HIFI 3663 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string multiplier = "M1" in ["M1","M2","M3"]; //Multiplier to be measured: M1, M2 or M3
}{
    //
    //Start_block(); 
    //Translate band name
    string band_new = Translate_band_name(band);
    string multiplier_code = multiplier + "_" + band_new;
    //
    {double,string}[] result = ConfigurationReader("name_delays",["lcu_iv_delay_m1","lcu_iv_delay_m2","lcu_iv_delay_m3"],"0",0.0);
    int lcu_iv_delay_m1 = iround(result[0]{0});
    int lcu_iv_delay_m2 = iround(result[1]{0});
    int lcu_iv_delay_m3 = iround(result[2]{0});
    //For M2_6b, 7a and 7b, we need 19 sec. more
    if(multiplier == "M2" && (band == "6b" || band == "7a" || band == "7b")) {
        lcu_iv_delay_m2 = lcu_iv_delay_m2 + 19;
    }
    if(multiplier == "M3" && band == "3b") {
        lcu_iv_delay_m3 = lcu_iv_delay_m3 + 11;
    }
    //We will use this delay as input for the TC.
    //Check M3 not called for inadequate bands
    bool go_ahead = true;
    if(multiplier == "M3" && band != "2a" && band != "2b" && band != "3a" && band != "3b" && band != "6a") {
        go_ahead = false;
    }
    if(go_ahead) {
        if(multiplier == "M1") {
            Hifi_HIFI_measure_LCU_IV($BBID,multiplier_code,lcu_iv_delay_m1);
            delay(lcu_iv_delay_m1);
        }
        if(multiplier == "M2") {
            Hifi_HIFI_measure_LCU_IV($BBID,multiplier_code,lcu_iv_delay_m2);
            delay(lcu_iv_delay_m2);
        }
        if(multiplier == "M3") {
            Hifi_HIFI_measure_LCU_IV($BBID,multiplier_code,lcu_iv_delay_m3);
            delay(lcu_iv_delay_m3);
        }
        // allow for the OBS to collect data AdJ 18-apr-2008
        delay(2);
    }
    //
}

// Procedure to compute the parameters needed in a Chopped HRS fast measurement
block Stability_chopped_fasthrs_block_ops HIFI 3440 {
    /* Integration time */
    string band = "1a"; // HIFI band
    double lo_freq = 522.0; // LO frequency
    int data_time = 10; // Chop phase length
    int n_data = 10; // Number of phases
    double hrs_readout = 0.333; // HRS readout length
    string chopper_pair = "load" in ["load","sky"]; //internal load or sky on-off
}{
    // Fixed backend configuration
    // No WBS
    int wbsh_offset1 = 0;
    int wbsh_width1 = 0;
    int wbsh_offset2 = 2048;
    int wbsh_width2 = 0;
    int wbsh_offset3 = 4096;
    int wbsh_width3 = 0;
    int wbsh_offset4 = 6144;
    int wbsh_width4 = 0;
    int wbsv_offset1 = 0;
    int wbsv_width1 = 0;
    int wbsv_offset2 = 2048;
    int wbsv_width2 = 0;
    int wbsv_offset3 = 4096;
    int wbsv_width3 = 0;
    int wbsv_offset4 = 6144;
    int wbsv_width4 = 0;
    string packing = "24_bits_format";
    // HRS
    int hrsh_sel = 128;
    //10000000 = 1U only
    int hrsv_sel = 128;
    //10000000 = 1U only
    // No bitshift
    int hrs_rshift = 0;
    int wbs_rshift = 0;
    // Timing - copied from ConfigSpectroscopyParams
    // Command jitter time is the default delay 
    {double,string}[] result = ConfigurationReader("name_delays",["add_jitter"],band,lo_freq);
    int add_jitter = iround(result[0]{0});
    // WBS delta time given by switch dead time
    double res = GetLoadChopDeadTime(band,lo_freq);
    // minimum delay
    int del_wbs = iceil(res * 1000.0);
    // HRS delta time - should be zero as well
    int del_hrs = add_jitter;
    // Additional delays in the readout loops - given in OBS user manual
    result = ConfigurationReader("name_delays",["add_hrs","add_wbs","add_jitter","wbs_init","wbs_chunksize","tacc_add","min_wbs_acc","scos_jitter"],band,lo_freq);
    int add_hrs = iround(result[0]{0});
    int add_wbs = iround(result[1]{0});
    int wbs_init = iround(result[3]{0}) + iround(result[7]{0});
    int wbs_chunksize = iround(result[4]{0});
    int tacc_add = iround(result[5]{0});
    int min_wbs_acc = iround(result[6]{0});
    // WBS transfer time
    // Split total integration time
    int tint = data_time * n_data * 1000;
    // dead time has to be an integer multiple of the 10ms chunk time
    int tdead = del_wbs + add_wbs + add_jitter;
    int nchunk = (tdead - 1) / wbs_chunksize + 1;
    int tcorr = nchunk * wbs_chunksize - tdead;
    del_wbs = del_wbs + tcorr;
    tdead = tdead + tcorr;
    // Accumulation time
    int t_acc_wbs = (tint - wbs_init) / n_data - tdead;
    // discretize in 10ms chunks
    nchunk = (t_acc_wbs - tacc_add) / wbs_chunksize;
    t_acc_wbs = nchunk * wbs_chunksize + tacc_add;
    // No WBS addition in ICU
    int n_wbs_integr = 1;
    int n_wbs_start = n_data;
    // HRS
    int hrs_phase = iceil(1000.0 * hrs_readout);
    int hrs_fullphase = hrs_phase + del_hrs + add_hrs;
    int r_hrs = (t_acc_wbs + hrs_fullphase - add_jitter) / hrs_fullphase;
    int t_acc_hrs = (t_acc_wbs - add_jitter) / r_hrs - del_hrs - add_hrs;
    // for n_wbs_integr=1 identical to r_hrs
    int n_hrs_integr = 1;
    // Issue configuration
    Hifi_HIFI_config_spectroscopy($BBID,n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,wbsh_offset1,wbsh_width1,wbsh_offset2,wbsh_width2,wbsh_offset3,wbsh_width3,wbsh_offset4,wbsh_width4,wbsv_offset1,wbsv_width1,wbsv_offset2,wbsv_width2,wbsv_offset3,wbsv_width3,wbsv_offset4,wbsv_width4,hrs_rshift,wbs_rshift,hrsh_sel,hrsv_sel,packing);
    //
    // Now call the spectroscopy
    //Get appropriate chopper voltages
    {bool,double,double} chopparms = GetChopVoltages(band,lo_freq,"chop_hot","chop_cold");
    if(chopper_pair == "sky") {
        chopparms = GetChopVoltages(band,lo_freq,"chop_M3right","chop_M3left");
    }
    bool isPrime = chopparms{0};
    // Call command
    if(isPrime) {
        Hifi_HIFI_P_Spectr_slow_chop($BBID,chopparms{1},chopparms{2});
    } else {
        Hifi_HIFI_R_Spectr_slow_chop($BBID,chopparms{1},chopparms{2});
    }
    delay(n_data * data_time + 3);
}

/////////////////////////////////////////////////////////////////
// Procedure to compute the detailed frequency grid for a
// spectral scan
{int,double,double[],int[][],int,bool} procedure MakeFreqGrid {
    string band = "4a"; // HIFI band
    double lo_freq_low = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4; // Frequency scan redundancy
    double freq_throw = 0.0; // Frequency throw in case of FSW observations
    int grouplen = 1; // Number of frequency steps before pointing to second phase
}{
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq_low,lo_freq_up);
    // Rigid check - not needed as scan will be reduced below
    // CheckLOFrequencies(band,lo_freq_low+min(freq_throw,0.0),
    //					lo_freq_up+max(freq_throw,0.0));
    // Get frequency grid characteristic parameters
    // Perform the check for the redundancy
    {double,int,double} gfref = GetFReference(band,lo_freq_low,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // Check that redundancy is allowed
    if(redundancy * increment != stdredun) {
        IError("The selected redundancy is no factor of " + stdredun + "!");
    }
    // Perform check for allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int maxgrouplen = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    if(grouplen > maxgrouplen) {
        SError("The group size exceeds the frequency range possible without recalibration.");
    }
    // We set up the frequency grid in four steps
    // Separate edges and main part of spectral scan
    {int,double,double} edgeampl = GetEdgeEnhance(redundancy,band);
    int highredun = edgeampl{0};
    int inchigh = stdredun / highredun;
    // Check that redundancy is allowed
    if(highredun * inchigh != stdredun) {
        IError("The required redundancy at the band edges cannot be satisfied!");
    }
    double nu1 = lo_freq_low;
    double nu2 = lo_freq_low + edgeampl{1};
    double nu3 = lo_freq_up - edgeampl{1};
    double nu4 = lo_freq_up;
    // Check for very small scans
    if(nu2 > nu4) {
        nu2 = nu4;
    }
    if(nu3 < nu1) {
        nu3 = nu1;
    }
    // Get frequency grid indices
    {int,int} ffindex = GetFScanBoundaries(band,freq_throw);
    {int,int} gfindex_lo = GetFIndex(band,nu1,nu2);
    {int,int} gfindex_up = GetFIndex(band,nu3,nu4);
    int index1 = gfindex_lo{0};
    int index2 = gfindex_lo{1};
    int index3 = gfindex_up{0};
    int index4 = gfindex_up{1};
    // Make frequency grid self-consistent and monotoneous
    // Shift if needed by frequency switch
    if(index1 < ffindex{0}) {
        index2 = index2 + ffindex{0} - index1;
        index1 = ffindex{0};
    }
    if(index4 > ffindex{1}) {
        index3 = index3 + ffindex{1} - index4;
        index4 = ffindex{1};
    }
    // Check again for very small scans
    if(index2 > index4) {
        index2 = index4;
    }
    if(index3 < index1) {
        index3 = index1;
    }
    //
    // lower frequency end with high redundancy
    int nstep1 = (index2 - index1 + inchigh - 1) / inchigh;
    index2 = index1 + nstep1 * inchigh;
    // Check again that we do not exceed the band boundary in this step
    if(index2 > ffindex{1}) {
        // No check here, we cannot exceed both boundaries
        index1 = index1 - index2 + ffindex{1};
        index2 = ffindex{1};
    }
    // upper end with high redundancy
    // Exception handling for small scans
    int nstep3 = imax((index4 - imax(index3,index2) + inchigh - 1) / inchigh - 1,0);
    index3 = index4 - nstep3 * inchigh;
    // main part inbetween, edges already covered
    int nstep2 = imax((index3 - index2 + increment - 1) / increment - 1,0);
    int index5 = index2 + nstep2 * increment;
    // Number of points
    int nfreq = nstep1 + nstep2 + nstep3 + 1;
    // Now we can construct the frequency grid from the index markers
    double[] freqgrid = GetFScanPoints(band,index1,index2,inchigh);
    // Consistency check
    if(nstep1 + 1 != length(freqgrid)) {
        CError("Frequency grid error. First frequency steps inconsistent.");
    }
    double[] addpoints = GetFScanPoints(band,index2,index5,increment);
    // Consistency check
    if(nstep2 + 1 != length(addpoints)) {
        CError("Frequency grid error. Main frequency steps inconsistent.");
    }
    for(int ia2 = 1 .. nstep2) {
        freqgrid[nstep1 + ia2] = addpoints[ia2];
    }
    addpoints = GetFScanPoints(band,index3,index4,inchigh);
    // Consistency check
    if(nstep3 + 1 != length(addpoints)) {
        CError("Frequency grid error. Last frequency steps inconsistent.");
    }
    if(nstep3 > 0) {
        for(int ia3 = 1 .. nstep3) {
            freqgrid[nstep1 + nstep2 + ia3] = addpoints[ia3];
        }
    }
    // Initial definition of the frequency grid finished
    // Check vs. system temperature and attenuators - modify if required
    double tsys = InterpolateTsys(band,reffreq);
    double[] tsysarray = GetAllTsys(band,freqgrid);
    // Search for frequencies with too high tsys
    double tsyslimit = GetTsysVariationLimit(band,reffreq);
    tsyslimit = tsys * tsyslimit;
    bool[] hightsys = [];
    int nadd = 0;
    for(int in1 = 0 .. nfreq - 1) {
        hightsys[in1] = tsysarray[in1] > tsyslimit;
        if(hightsys[in1]) {
            nadd = nadd + 1;
        }
    }
    // Add some integrations to make the total number of points an
    // integer multiple of the group size
    int groupnumber = (nfreq + nadd + grouplen - 1) / grouplen;
    int nrest = groupnumber * grouplen - nfreq - nadd;
    // add integrations at points of highest system temperature not yet covered
    for(int ng = 1 .. nrest) {
        int curmax = -1;
        double tsysmax = 0.0;
        for(int in2 = 0 .. nfreq - 1) {
            // dont duplicate points which are already duplicated
            if(!hightsys[in2]) {
                // search for maximum
                if(tsysarray[in2] > tsysmax) {
                    curmax = in2;
                    tsysmax = tsysarray[in2];
                }
            }
        }
        if(curmax >= 0) {
            // Add point
            hightsys[curmax] = true;
        } else {
            // Giving up
            string obscure = "Perfect observation! You managed to set up the " + "observation that will explain life, the universe, and everything. " + "However, as this would drastically lower future research funding, " + "the observation is rejected. ";
            // Throw message
            IError(obscure + "Please, increase frequency interval or reduce redundancy!");
        }
    }
    // Actually expand frequency grid
    int newindex = 0;
    double[] newgrid = [];
    for(int in3 = 0 .. nfreq - 1) {
        newgrid[newindex] = freqgrid[in3];
        newindex = newindex + 1;
        if(hightsys[in3]) {
            newgrid[newindex] = freqgrid[in3];
            newindex = newindex + 1;
        }
    }
    // Consistency check
    nfreq = nfreq + nadd + nrest;
    if(nfreq != length(newgrid)) {
        CError("Frequency grid error. Expanded frequency grid inconsistent.");
    }
    // Information about frequency grid
    message("Actually covered frequency range: " + newgrid[0] / 1000.0 + " - " + newgrid[nfreq - 1] / 1000.0 + "GHz.<br>");
    // Summary message
    message("Total number of LO settings: " + nfreq + "<br>");
    // Create index for frequency stepping within a group  
    int[][] grouporder = GetFrequencyGroupSteps(grouplen);
    // Check for very small scans
    if(lo_freq_up - lo_freq_low >= edgeampl{1} + edgeampl{2}) {
        bool dsb = true;
        int nfreq_if = redundancy;
    } else {
        if(lo_freq_up - lo_freq_low >= edgeampl{2}) {
            dsb = false;
            nfreq_if = highredun;
        } else {
            dsb = false;
            nfreq_if = nfreq;
        }
    }
    // Final sanity check
    CheckSpectralScanRange(band,reffreq,newgrid[0],newgrid[nfreq - 1]);
    // Return all frequency parameters

    return {groupnumber,reffreq,newgrid,grouporder,nfreq_if,dsb};
}

//Set LOU to nominal, procedure
//Set LOU in nominal mode with no channel selected
procedure Set_LO_Nominal_proc_aot {
}{
    {double,string}[] result = ConfigurationReader("name_delays",["set_to_nominal_delay"],"0",0.0);
    int set_to_nominal_delay = iround(result[0]{0});
    //
    Hifi_HIFI_HL_Normal($BBID);
    delay(set_to_nominal_delay);
    //
}

// Compute minimum nod time in a nod used for loads
// Used only in case of scansize > 1
int procedure GetMinLoadNod {
    int[] telescopetimes = [300,180,20,0,21,0,4,10,10,10];
    int scansize = 2; // Number of points measured in one scan
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF pointing cycles
    int n_loadinterval = 1; // Number of nods to include loads
}{
    // Use telescope return parameters
    int numpoints = telescopetimes[6];
    // Scan return field
    int n_scans = numpoints / (2 * scansize);
    int n_loadnods = n_scans / n_loadinterval;
    int longslew = 180;
    // guarantee that all nods are shorter
    for(int i1 = 0 .. n_loadnods - 1) {
        int theindex = 6 + scansize + i1 * (n_loadinterval * 2 * scansize);
        longslew = imin(longslew,telescopetimes[theindex]);
    }

    return longslew;
}

// WBS attenuator tuning, procedure
// Both polarizations are treated
procedure WBS_tune_proc_fm {
    string band = "1a"; // HIFI band
}{
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["tune_target"],band,0.0);
    int tune_target = iround(result_d[0]{0});
    //
    //Now tune attenuators.
    WBS_tune_block_fm(band,tune_target);
    //
}

//Set LCU4b back to standby status, procedure
procedure LCU4b_standby_proc_fm {
    string band = "4b"; // HIFI band
    double lo_freq = 1100.0 in [1056.0,1113.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

// Step 1 of QLA_Testcontrol coarse magnet-tuning loop
// Bias current at low bias
block Magnet_scan_coarse_fm HIFI 3201 {
    string band = "1a";
}{
    Start_block();
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["magnet_current_min_h","magnet_current_max_h","magnet_steps_h","magnet_step_duration_h","bias_very_low_h","magnet_current_min_v","magnet_current_max_v","magnet_steps_v","magnet_step_duration_v","bias_very_low_v"],band,0.0);
    //H polar
    double magnet_min_h = result_d[0]{0};
    double magnet_max_h = result_d[1]{0};
    int steps_h = iround(result_d[2]{0});
    double step_time_h = result_d[3]{0};
    double bias_h = result_d[4]{0};
    //V polar
    double magnet_min_v = result_d[5]{0};
    double magnet_max_v = result_d[6]{0};
    int steps_v = iround(result_d[7]{0});
    double step_time_v = result_d[8]{0};
    double bias_v = result_d[9]{0};
    //
    double step_time = max(step_time_h,step_time_v);
    //
    Magnet_scan(band,magnet_min_h,magnet_max_h,steps_h,step_time,bias_h,magnet_min_v,magnet_max_v,steps_v,bias_v);
}

//HIFI Housekeeping ON, block
//I set 1 fixed rate of 1 packet per sec.
block HIFI_Housekeeping_on_block_fm HIFI 3656 {
}{
    Start_block_no_hk_request();
    //Get applicable HK rate
    {double,string}[] result_d = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    string hk_rate = result_d[0]{1};
    Hifi_HIFI_Housekeeping_on(hk_rate,"ON","ON","ON","ON","ON","ON");
    delay(1);
}

//HIFI-COP-7.1-FT: Regular FT during Commissioning for Temp. trend monitoring
procedure TrendMon_FT_COP_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    string[] band = ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"];
    //
    //1. FT unpumped
    //General parameters in use
    int integ_time = 4;
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    for(int i = 0 .. 6) {
        //For bands 6 and 7, use wb8
        if(band[2 * i] == "6a" || band[2 * i] == "7a") {
            hrs_mode = ["wb8","wb8"];
        }
        FT_unpumped(band[2 * i],hrs_mode,integ_time,backend);
    }
    //2. IF feeb-back in one band: band 5a
    double lo_freq = 1116.0;
    hrs_mode = ["wb1","wb1"];
    integ_time = 604;
    IF_FBk_COP_proc_ops(band[8],lo_freq,hrs_mode,integ_time,backend);
    //3. IF stability in one SIS band: band 1a
    int n = 751;
    //Number of load pairs to be measured
    string mixer_polarization = "B";
    //Polarization: H, V, or both (B) 
    integ_time = 4;
    //Use high biases
    {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_high_resistive_h"],band[0],0.0);
    Proc_stability_IF_system(band[0],n,hrs_mode,mixer_polarization,integ_time,backend,result[0]{0});
    //Repeat for band 6a
    result = ConfigurationReader("name_confilfpu",["bias_high_resistive_h"],band[10],0.0);
    Proc_stability_IF_system(band[10],n,hrs_mode,mixer_polarization,integ_time,backend,result[0]{0});
}

// Get the standard chop angle difference from calibration file
double[] procedure GetSkyChopThrow {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    string throw = ""; // Identifier for chop throw, empty is standard
}{
    string lstring = throw + "length";
    string astring = throw + "angle";
    double[] nodpatt = CalibrationReader("skychopthrow",[lstring,astring],band,lo_freq);
    // We chop now from plusZ tu minusZ, i.e. in negative direction
    double patt = nodpatt[1] + 180.0;
    // restrict to allowed range
    patt = (patt + 360.0) % 360.0;

    return [nodpatt[0],patt];
}

//////////////////////////////////////////////////////////////////////////
// Procedure to generate the telescope command inherited from DBS mode
////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure FastDBS_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 10 in [4,80]; // data dump interval
    int n_int = 20; // number chop cycles to integrate in ICU before transfer
    int n_seq = 1; // Number of continuous data transfer cycles
    int n_load = 0; // additional load measurements in one pointing phase
    int n_loadinterval = 10; // number of nods before a load measurement
    bool end_load = false; // Need for load after each pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    int shiftlength = 10; // Shift of the loop start relative to the pointing
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Fixed timings in the fast-chop mode
    int load_datatime = GetStdLoadReadout(band,lo_freq);
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time / 2);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,true);
    int readoutdead = FastChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    int[] choppars = [2 * n_int,0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength + shiftlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            if(shiftlength > 0) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i1 = 1 .. n_load) {
                HIFIFastChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFIFastChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            // Second phase in first nod position
            // occurs for even cycle numbers
            runintostate = false;
            if(state[2] % 2 == 0) {
                if(end_load) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // A nod slew follows - active HK if not used by load measurement
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 7) {
            // second nod position
            choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i2 = 1 .. n_load) {
                HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            // First phase in second nod position
            // occurs for odd cycle numbers
            runintostate = false;
            if(state[2] % 2 == 1) {
                if(end_load) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // A nod slew follows - active HK if not used by load measurement
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            runintostate = false;
        }
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                // ( Does not occur if end_load is set)
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

// Very fast sampling stability measurement combined with int-load-chop
// Uses only the HRS in wb mode
procedure Stability_chopped_fasthrs_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 522.0; // LO frequency
    int phaselength = 10; // Chop phase length
    int nchop = 10; // Number of phases
    double readout = 0.333; // HRS readout length
    double[] hrs_subband = [5.0,5.0,5.0,5.0]; //Positions in IF of HRS sub-bands
    string chopper_pair = "load" in ["load","sky"]; //internal load or sky on-off
    string polarization = "B"; //mixer to be sampled: H, V or B. If B, they are done successively
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 50;
    int samplesAfter = 1000;
    string with_lo_on = "true" in ["true","false"]; //Whether measurement with LO ON or not
}{
    // Clean  HK treatment for controlled data rates
    HIFISetHK("fast",false);
    {string,int,double,double,double,double} hkparms = PeriodicHKParms("fast");
    // HK data: stdrate=7744+864+2*272, IF packets=2*(592+272)
    int allhkbits = 1782;
    double hkrate = hkparms{3} + double(allhkbits) / readout;
    // Science data: 2*(2*258*24+1376+3*272)
    int allbits = 29152;
    double sciencerate = double(allbits) / readout;
    // set data rates
    ess_hk_data_rate(hkparms{5} / 1024.0);
    non_ess_hk_data_rate(hkrate / 1024.0);
    data_rate(sciencerate / 1024.0);
    //Configure HRS: regardless of selected bands
    HRS_config_resol_block_fm(band,["wb1","wb1"]);
    HRS_config_att_lo_w_lo_input_block_fm(band,["wb1","wb1"],hrs_subband);
    //Prepare chopper position for HRS attenuator tuning
    if(chopper_pair == "load") {
        Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
        //Look at HBB
    } else {
        Chopper_Rotation_block_fm(band,"chop_hot_ang","chop_M3_ang");
        //Look at sky
    }
    //measurement without LO
    if(with_lo_on == "false") {
        //Force LO swith-off
        LCU_switch_off_block_fm();
        //FPU configuration
        if(chopper_pair == "load") {
            Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
        } else {
            Init_MSA_SKY_fm(band,"CLOSE",lo_freq,"ON");
        }
        //For HEBs, set bias to 3mV
        if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
            {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
            Mixerbias_block_fm(result[0]{0},result[1]{0});
            result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v"],band,lo_freq);
            Mixerbias_block_fm(result[0]{0},result[1]{0});
        }
        //Fast Imix measurement: only if option load
        if(chopper_pair == "load") {
            Fast_Imix_block_fm(band,polarization,milliSecSample,samplesBefore,samplesAfter);
        }
        //Backend tuning without LO
        HRS_tune_block_fm(band);
        // Run the actual chopped fast-HRS interation
        Stability_chopped_fasthrs_block_ops(band,lo_freq,phaselength,nchop,readout,chopper_pair);
    } else {
        //measurement with LO
        //LO swith-on
        LCU_switchon_proc_fm(band);
        //Wait an extra delay of 1 min for short term stabilization
        delay(60);
        //FPU configuration
        if(chopper_pair == "load") {
            Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
        } else {
            Init_MSA_SKY_fm(band,"CLOSE",lo_freq,"ON");
        }
        //LO tuning
        LO_tuning_block_fm(band,lo_freq);
        //Fast Imix measurement: only if option load
        if(chopper_pair == "load") {
            Fast_Imix_block_fm(band,polarization,milliSecSample,samplesBefore,samplesAfter);
        }
        //Backend tuning with LO
        HRS_tune_block_fm(band);
        // Run the actual chopped fast-HRS interation
        Stability_chopped_fasthrs_block_ops(band,lo_freq,phaselength,nchop,readout,chopper_pair);
    }
    // reset data rates
    non_ess_hk_data_rate(hkparms{3} / 1024.0);
    data_rate(0.0);
}

// IV curve, block
block IVcurve_general_fm HIFI 3210 {
    string band = "1a";
    double lo_freq = 522.0; //LO frequency  
    double bias_min = -6.0;
    double bias_max = 6.0;
    int steps = 131;
}{
    //Start_block() ;
    //Fetch values for magnets and bias
    if(band == "0") {
        {double,string}[] result_d = ConfigurationReader("name_confilfpu",["bias_standby_h","bias_standby_v","magnet_standby_h","magnet_standby_v"],band,0.0);
    } else {
        if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
            result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v","norm_magn_h","norm_magn_v"],band,lo_freq);
        } else {
            result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        }
    }
    double bias_h = result_d[0]{0};
    double bias_v = result_d[1]{0};
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        double magnet_current_h = result_d[2]{0};
        double magnet_current_v = result_d[3]{0};
    } else {
        magnet_current_h = 0.0;
        magnet_current_v = 0.0;
    }
    //
    IVcurve(band,bias_min,bias_max,steps,magnet_current_h,magnet_current_v,bias_h,bias_v);
}

////////////////////////////////////////
// Procedure to calculate the pre timing
//
{int,int,int,int,int,int,int,int,int,bool,int,int,int} procedure FastDBS_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 10 in [4,80]; // data dump interval
    int n_int = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_data = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Fixed timings in the fast-chop mode
    int load_datatime = GetStdLoadReadout(band,lo_freq);
    // It should be investigated wehther we can use fast-chop on loads as well
    // Perform consistency checks
    int single_data = data_time / 2;
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,single_data);
    // Check chopper frequency
    CheckFastChopFrequency(band,lo_freq,data_time,n_int,n_data);
    // Telescope-instrument communication jitter
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    // Compute parameters for the instrument timing
    int readouttime = data_time;
    int inttime = data_time * n_data;
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms));
    int readoutdead = FastChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // For double phases I can use the added jitterdead in both phases for load
    int halfloadlength = (loadlength - jitterdead + 1) / 2;
    // Compare load interval and nodding interval
    // This determines the order of the loops
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    if(load_spacing < data_time) {
        SError("Load period shorter than backend readout period.");
    }
    int n_load = inttime / load_spacing;
    if(load_spacing > 2 * inttime) {
        int n_seq = n_data;
        bool end_load = false;
        int pointing = inttime + jitterdead;
        int shiftlength = 0;
    } else {
        n_seq = n_data / (n_load + 1);
        if(n_seq < 1) {
            SError("Transfer cycle too long relative to load period.");
        }
        end_load = true;
        inttime = n_seq * (n_load + 1) * data_time;
        pointing = inttime + halfloadlength + n_load * loadlength + jitterdead;
        shiftlength = halfloadlength;
    }
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,true);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,false);
    }
    initlength = initlength + loadlength;
    // Compute the overall cycle length
    // First estimate of the load interval
    int n_loadinterval = imax(load_interval / (2 * pointing),1);
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed for telescope call and post_timing processing

    return {inttime,pointing,readouttime,loadlength,jitterdead,load_spacing,n_load,n_loadinterval,n_seq,end_load,shiftlength,initlength,dangling};
}

//////////////////////////////////////////////////////////////////////////
// Procedure to generate the telescope command is inherited from load chop
////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure FSwitchNoRef_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval limited by the data rates
    int n_per_on = 1; // number of half load-sky-sky-load cycles on ON
    int n_load_on = 0; // additional load measurements in ON pointing phase
    bool end_load_on = false; // Need for load after ON pointing phase
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,0]; // Timing of observation from telescope
    int loadlength = 50; // Load duration
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFIFsw(band,lo_freq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // ON integration
            HIFIConfigureFSwitchIntegration(data_time,n_per_on,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i1 = 1 .. n_load_on) {
                HIFIFSwitchOnIntegration(data_time,n_per_on,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureFSwitchIntegration(data_time,n_per_on,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFIFSwitchOnIntegration(data_time,n_per_on,band,lo_freq,rates);
        }
        if(state[0] == 5) {
            delay(readoutdead);
            if(end_load_on) {
                // Perform final load measurement 
                DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
            }
            HIFICloseObs();
        }
    }
}

// get HRS efficiency
double procedure GetHrsEfficiency {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] resol = CalibrationReader("backendresolution",["hrs_efficiency"],band,lo_freq);

    return resol[0];
}

// Initialisation of FPU, block with both MSA in use
// It is for warm context !
block Init_MSA_fm_dummy HIFI 3220 {
    string band = "1a"; // HIFI band
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReaderWarm("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReaderWarm("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    //Get biases
    result_d = ConfigurationReaderWarm("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReaderWarm("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReaderWarm("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode","diplexer_current_normal_h","diplexer_current_normal_v"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        //double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_d[2]{0};
        //result_dip[0];
        diplex_V = result_d[3]{0};
        //result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReaderWarm("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    Hifi_HIFI_non_periodic_hk_FCU();
}

// WBS stand-by, block
block WBS_standby_fm HIFI 3703 {
    string band = "1a"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
}{
    //Start_block(); 
    //Set zero ON
    Hifi_HIFI_switch_zero_WBS_H($BBID,"ON");
    Hifi_HIFI_switch_zero_WBS_V($BBID,"ON");
    delay(1);
    //Standby configuration
    //H-Polarization
    //
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = 0;
    //000
    string hwh_latchup_s = "Level1";
    int hwh_att_band4 = 7;
    int hwh_att_band3 = 7;
    int hwh_att_band2 = 7;
    int hwh_att_band1 = 7;
    int hwh_att_in = 15;
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    {double,string}[] result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = 0;
    //000
    string hwv_latchup_s = "Level1";
    int hwv_att_band4 = 7;
    int hwv_att_band3 = 7;
    int hwv_att_band2 = 7;
    int hwv_att_band1 = 7;
    int hwv_att_in = 15;
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
}

/////////////////////////////////////////////////////////////////
// Auxiliary routine to determine the two loop phase durations for all
// DBS modes
{double,double} procedure DBSPhaseLengths {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
}{
    // Get the drift parameters to compute the drift noise
    if(continuumDetection) {
        double[] allanparms = InterpolateTpAllan(band,lo_freq,oneGHzReference);
    } else {
        allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    }
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // Differential Allan variance
    if(continuumDetection) {
        allanparms = InterpolateTpChopAllan(band,lo_freq,oneGHzReference);
    } else {
        allanparms = InterpolateSpecChopAllan(band,lo_freq,oneGHzReference);
    }
    // rescale to frequency resolution
    double dalpha = allanparms[1];
    binningexp = 1.0 / allanparms[2];
    double dallan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // phase lengths
    double main_phase = 0.3 * dallan_time_lores;
    double chop_phase = 0.3 * allan_time_lores;
    // Constrain by load period
    int loadper = LoadPeriod(band,lo_freq,effResolution{0});
    main_phase = min(main_phase,0.4 * double(loadper));

    return {main_phase,chop_phase};
}

// Get main beam size for message 
double procedure GetTsysVariationLimit {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] fwhm = CalibrationReader("tsysvariation",["tsysvariation"],band,lo_freq);

    return fwhm[0];
}

// WBS comb, block
block WBS_comb_fm HIFI 3605 {
    string band = "1a"; // HIFI band
}{
    //Start_block(); 
    //Two options are possible: CUS sequence or automatic OBS command
    //Option1: CUS sequence
    //WBS_comb_fm_proc(band,backend);
    //Option2: OBS command. It takes attenuators as input as well.
    //We have to set attenuators to values different from max.
    //Initial configuration
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_att_band4_comb","hwh_att_band3_comb","hwh_att_band2_comb","hwh_att_band1_comb","hwh_att_in_comb","hwv_att_band4_comb","hwv_att_band3_comb","hwv_att_band2_comb","hwv_att_band1_comb","hwv_att_in_comb"],band,0.0);
    int hwh_att_band4 = iround(result_d[0]{0});
    int hwh_att_band3 = iround(result_d[1]{0});
    int hwh_att_band2 = iround(result_d[2]{0});
    int hwh_att_band1 = iround(result_d[3]{0});
    int hwh_att_in = iround(result_d[4]{0});
    int hwv_att_band4 = iround(result_d[5]{0});
    int hwv_att_band3 = iround(result_d[6]{0});
    int hwv_att_band2 = iround(result_d[7]{0});
    int hwv_att_band1 = iround(result_d[8]{0});
    int hwv_att_in = iround(result_d[9]{0});
    //    
    Hifi_HIFI_WBS_Comb($BBID,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //Apply delay
    result_d = ConfigurationReader("name_delays",["wbs_comb_delay"],band,0.0);
    int wbs_comb_delay = iround(result_d[0]{0});
    delay(wbs_comb_delay);
    //
}

//Notify PDU status ON, block
//I assume all S/S are present
block HIFI_notify_PDU_status_on_block_fm HIFI 3655 {
    string status_FCU = "ON" in ["ON","OFF"]; //Status of FCU
    string status_LCU = "ON" in ["ON","OFF"]; //Status of LCU
    string status_WBSV = "ON" in ["ON","OFF"]; //Status of WBSV
    string status_WBSH = "ON" in ["ON","OFF"]; //Status of WBSH
    string status_HRSV = "ON" in ["ON","OFF"]; //Status of HRSV
    string status_HRSH = "ON" in ["ON","OFF"]; //Status of HRSH
}{
    Start_block_no_hk_request();
    Hifi_HIFI_notify_PDU_status(status_FCU,status_LCU,status_WBSV,status_WBSH,status_HRSV,status_HRSH);
    delay(1);
}

//Load new OBSW , block
block Load_OBSW_block_ops HIFI 7927 {
}{
    mois_comment("Assign obsid number to procedure execution");
    mois_spacon("In the following command, the second parameter (OBS_ID) shall be replaced by a Formal Parameter value according to the list provided by the instrument ICC.");
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    //  
    mois_step("Construct the OBSW copy");
    mois_spacon("Use the OBSM to prepare the HIFI_load_PRAM TC list to build the new version of the OBSW that is to be loaded and started");
    //
    mois_step("Upload the OBSW copy to PM-high");
    mois_spacon("Use the OBSM to run the TC list previously prepared to load the new version of the OBSW. Please be aware at the copy should start from address 0x3ffff.");
    //
    mois_step("Verify integrity of copied OBSW");
    //Check PM memory for OBS 5.3: need to put offsets of starting address for PM high
    mois_spacon("In the following command, the three parameters will be replaced by Formal Parameters provided by the instrument ICC.");
    int check_start = 0x5500 + 0x3ffff;
    int check_end = 0x17ff1 + 0x3ffff;
    int check_crc = 0xd32;
    Hifi_HIFI_check_PM_memory(check_start,check_end,check_crc);
    delay(3);
    mois_spacon("Checks TBD");
    //
    mois_step("Copying uploaded OBSW to DM-low");
    int hifi_OBS_destination = 0x3ffff;
    // OBS_destination: start of PM high
    int hifi_OBS_copy_length = 0x20000;
    // OBS_copy_length
    Hifi_HIFI_copy_mem_to_low(hifi_OBS_destination,hifi_OBS_copy_length);
    delay(1);
    //The new OBSW should be booted
    mois_tmcheck("Check that the new OBSW release numbers have been updated (HI_SW_Version, HI_SW_Revision and HI_SW_Patch)");
}

// Perform frequency-switch integration  at ON position
block HIFIFSwitchOnIntegration HIFI 6038 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_fswitch_proc_aot(data_time,n_cycle,band,lo_freq,rates);
}

//////////////////////////////////////////////////////////////////////
// Compatibility procedure to provide the same API as used in
// the previous versions
//
// Returns the actual integration time and the dead time per phase
{{double,double,double},{int,int}} procedure ConfigSpectroscopyFastChop {
    /* Integration time */
    double data_chop = 0.5 in [0.1,2.0]; // Length of a single chop phase
    int n_int = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string band = "1a"; // HIFI band
    double lo_freq = 522000.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used,channel windows} 
}{
    // Translate data_chop into new parameter data_time (approximate)
    // Get auxiliary quantities
    {double,string}[] result = ConfigurationReader("name_delays",["add_wbs","add_jitter","wbs_readout","wbs_init","scos_jitter"],band,lo_freq);
    int add_wbs = iround(result[0]{0});
    int add_jitter = iround(result[1]{0});
    int wbs_readout = iround(result[2]{0});
    int wbs_init = iround(result[3]{0}) + iround(result[4]{0});
    int tdead_data = 2 * (wbs_readout + add_jitter) + add_wbs - add_jitter;
    int totaltime = (iceil(1000.0 * data_chop) * 2 * n_int + tdead_data) * n_data + wbs_init;
    totaltime = iceil(double(totaltime) / 1000.0);
    int data_time = (totaltime + n_data - 1) / n_data;
    // Check
    CheckFastChopFrequency(band,lo_freq,data_time,n_int,n_data);
    // Get timing parameters
    bool wbs_used = backendreadoutparms{2}{0} || backendreadoutparms{3}{0};
    {int,int,int,int,int,int,int,int,int,int,int,int,int} timing = FastConfigureSpectroscopyParams(data_time,n_int,n_data,band,lo_freq,wbs_used);
    int n_wbs_start = timing{0};
    int r_hrs = timing{1};
    int n_wbs_integr = timing{2};
    int n_hrs_integr = timing{3};
    int del_hrs = timing{4};
    int del_wbs = timing{5};
    int t_acc_wbs = timing{6};
    int t_acc_hrs = timing{7};
    int n_wbs1 = timing{8};
    int n_hrs_trans = timing{9};
    int tdead_chop = timing{10};
    tdead_data = timing{11};
    int tint_act = timing{12};
    {int,int,int,int,int[],int[],string} backendconfigure = ConfigSpectroscopyBackends(data_time,backendreadoutparms);
    int wbs_rshift = backendconfigure{0};
    int hrs_rshift = backendconfigure{1};
    int hrsh_sel = backendconfigure{2};
    int hrsv_sel = backendconfigure{3};
    int[] wbsh_par = backendconfigure{4};
    int[] wbsv_par = backendconfigure{5};
    string packing = backendconfigure{6};
    // Now call the command
    Hifi_HIFI_config_spectroscopy($BBID,n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,wbsh_par[0],wbsh_par[1],wbsh_par[2],wbsh_par[3],wbsh_par[4],wbsh_par[5],wbsh_par[6],wbsh_par[7],wbsv_par[0],wbsv_par[1],wbsv_par[2],wbsv_par[3],wbsv_par[4],wbsv_par[5],wbsv_par[6],wbsv_par[7],hrs_rshift,wbs_rshift,hrsh_sel,hrsv_sel,packing);
    //
    // Return dead times and comand parameters

    return {{double(tint_act) / 1000.0,double(tdead_chop) / 1000.0,double(data_time * n_data)},{n_wbs1,n_hrs_trans}};
}

//////////////////////////////////////////////////////////////////////////////
// routines from ILT not used in observing modes
//////////////////////////////////////////////////////////////////////////////
//Configure LCU in nominal mode at frequency of interest
procedure ConfigureLOUnominal {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
}{
    LCU_config_nominal_proc_aot(band,lo_freq / 1000.0);
}

// =======================================================
// These are the CUS by Moncef - extracted from the CUS
// import done by Albrecht.
// Modifications wrt Albrecht´s corrections:
// 	- I have suppressed all the capital letters in order to
// 	be compatible with the name in the configuration files
//	- Some BBID are already used by other blocks. I set
//	everything to 1501 upwards.
// DT - 24 Sept 2004
//	29 Sept 2004: Remark: nothing is done for V polar !
//	18 July 2005: Adapted for FM - both polar treated
// ========================================================
//Modes: see fm_testmodes.cus
//========================================================
// BLOCKS
//========================================================
// BLOCK : Functional Test No 0 (HRS Switch ON)
block HRS_functional_test_No_0_block_fm HIFI 3610 {
}{
    //Start_block();
    //
    //Use new command implemented in SCR-859
    Hifi_HIFI_HRS_functional_test($BBID,0,"BOTH");
    delay(5);
    //
}

//  LCU5b configuration and tuning, procedure
procedure LCU5b_config_tune_proc_fm {
    string band = "5b"; // HIFI band
    double lo_freq = 1200.0 in [1192.0,1242.0]; //LO frequency
    double drain_2_factor = 100.0; //Percentage factor of the targetted drain voltage
}{
    error("This module is obsolete: use LO_tuning_block_fm  instead");
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure SScanChopNoRef_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int nfreq = 4; // Number of frequency points per IF
    bool dsb = true; // Both sidebands covered
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int n_cycles = 1; // Number of chop cycles
    int freqsteps = 4; // Total number of frequencies
    bool fs = false; // whether frequency switch used
    double tscan = 10.0; // Total average duration of one scan
    double tdead = 0.05; // Average dead time in one chop cycle
}{
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    // Use DSB noise for long spctral scans
    if(dsb) {
        double idealnoiselsb = idealvalues{1} * idealvalues{1};
        double idealnoiseusb = idealvalues{3} * idealvalues{3};
        double idealnoise = idealnoiselsb * idealnoiseusb / (idealnoiselsb + idealnoiseusb);
    } else {
        idealnoise = idealvalues{1} * idealvalues{1};
    }
    double obsnoise = noisevalues{0} * noisevalues{0};
    // rescale for range coverage
    double accumulation = double(freqsteps) / double(nfreq);
    idealnoise = idealnoise * accumulation;
    double efficiency = idealnoise / obsnoise;
    // Compute the actual integration time
    double inttime = (tscan - tdead) / 2.0;
    double posinttime = double(n_cycles) * 2.0 * inttime * double(freqsteps);
    double posofftime = 0.0;
    int instrumenttime = iceil(double(freqsteps) * tscan);
    // Check total integration time
    double timeefficiency = (posinttime + posofftime) / double(totaltime);
    // Noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posofftime,timeefficiency,efficiency,relnoise,fs);
}

//General LO configuration command
block HIFI_Configure_LCU_ALL_block_fm HIFI 3670 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    int freq_nx = 0; // HL_freq_nx
    int lsu_main = 0; // HL_LSU_main
    int lsu_offset = 0; // HL_LSU_offset
    int d2_step = 1; // HL_D2_step
    double plevel_v = 0.0;
    double m1_v = 9.0;
    double m2_v = -2.0;
    double m3_v = 0.0;
    double gate1_v = -2.5;
    double gate2_v = -2.5;
    double drain1_v = 2.8;
    string curlim1_v = "1.4";
    double drain2_v = 2.6;
    string curlim2_v = "1.4";
    int macro_checksum = 0; // HL_macro_checksum
    int config_lo_delay = 6;
}{
    //Check that Vd2 is within the blue limits
    drain2_v = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v);
    //
    //Start_block(); 
    //
    //Execute configuration
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_nom_LCU_ch1a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_nom_LCU_ch1b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_nom_LCU_ch2a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_nom_LCU_ch2b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_nom_LCU_ch3a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_nom_LCU_ch4a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_nom_LCU_ch4b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
    delay(config_lo_delay);
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//HIFI-COP-7.1-FT: Regular FT during Commissioning for Temp. trend monitoring
obs HifiEng_TrendMon_FT_COP {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(TrendMon_FT_COP_proc_ops(prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            TrendMon_FT_COP_proc_ops(prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//Chopper health check: step#2
procedure Chopper_FT2_COP_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Chopper health check: needs to start in open loop
    double lo_freq = 0.0;
    double chopper_voltage = 0.0;
    Init_MSA_ops("0","OPEN",lo_freq,chopper_voltage,"ON",prime_or_redundant);
    Chopper_openloop_scan_block_ops(prime_or_redundant);
    //
}

// Frequency of load measurements 
// This is no longer computed, but tabulated as it does not depend
// on user parameters - deltanu is a dummy parameter
int procedure LoadPeriod {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    double deltanu = 1.0; // maximum effective resolution of the calibrated data
}{
    // Get the stability parameters
    double[] allanparms = CalibrationReader("loaddiff_stability",["tp_stability_time"],band,lo_freq);
    int period = ifloor(allanparms[0]);

    return period;
}

//HIFI-COP-2.1-DipCal1
obs HifiEng_Diplexer_calibration_vs_D2_COP {
    string band = "3" in ["3","4","6","7"]; // HIFI mixer band
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Diplexer_calibration_vs_D2_proc_fm(band));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Diplexer_calibration_vs_D2_proc_fm(band);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// HRS attenuator tuning, block
// Both polarizations are treated
block HRS_tune_fast_block_fm HIFI 3991 {
    string band = "1a"; // HIFI band
    int hrstunedelay = 2; //delay used to perform the HRS tuning
}{
    //Start_block();
    //First //de-select HRS HK
    Hifi_HIFI_Housekeeping_on("1_pkt_per_s","ON","ON","ON","ON","OFF","OFF");
    //Now tune attenuators: it sets the HRS to ultra_wide
    Hifi_HIFI_Tune_HRS($BBID);
    delay(hrstunedelay);
    //
    //Switch on HRS HK polling back
    Hifi_HIFI_Housekeeping_on("1_pkt_per_s","ON","ON","ON","ON","ON","ON");
}

//Force boot, block
block HIFI_force_boot_block_ops HIFI 7600 {
    int partition_ID = 0; //0 if forceboot_default. Partition ID in case it should be used. 
}{
    if(partition_ID == 0) {
        mois_comment("ICU booted using default partition.");
        Hifi_HIFI_force_bootdefault();
    } else {
        mois_comment("ICU booted using partition # " + partition_ID);
        Hifi_HIFI_force_bootpartition(partition_ID);
    }
    mois_tmcheck("Verify HIFI HK telemetry packets (3,25,1025) - HIFI_PERIODIC_HK - are arriving every 4 seconds.");
    //mois_tmcheck("Verify that no (5,4) telemetry packet has been received from HIFI.");
    //Increase delay - SPR-1354
    delay(5);
    //This is not standard practice but here we can only start
    //to stamp HKs with obsid/bbid pair after ICU is up and running
    //StartBlock_ops();   //removed for moc_cus_1.3 because the next block asks for this already
}

//Retune HIFI for frequency switch - keep magnet and backends
procedure HIFITuneFreqNoretuneFsw {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq_1 = 978200.0; //LO frequency for FSW1 phase
    double lo_freq_2 = 978300.0; //LO frequency for FSW2 phase
}{
    // Setting with no retune for first frequency, and store in FSW1 register
    LCU_config_nominal_noretune_block_aot(band,lo_freq_1 / 1000.0,true);
    //
    // Second frequency setup, and stored in FSW2 register
    LCU_config_nominal_noretune_block_aot(band,lo_freq_2 / 1000.0,true);
    //
}

//Startblock
procedure Start_block_no_hk_request {
}{
    //These are ILT-EGSE commands, not ruled by the 2TC/sec.
    //HifiIltEgse_FPU_set_BB_ID($BBID);
    //HifiIltEgse_PDU_set_BB_ID($BBID);
    //SpireIltEgse_QCC_SETBBID($BBID);
    //delay(1);
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    //Hifi_HIFI_non_periodic_hk_FCU();
    delay(1);
}

//  LCU switch-off, procedure
procedure LCU_switch_off_proc_fm {
}{
    //
    //Automatic failure mode clearance.
    //Should take <0.5s so time included in the switch-off delay
    Hifi_HIFI_HL_Normal($BBID);
    //
    {double,string}[] result = ConfigurationReader("name_delays",["switch_off_delay"],"0",0.0);
    int switch_off_delay = iround(result[0]{0});
    //
    //Send command: this is the effective switch-off
    Hifi_HIFI_Conf_nom_LCU_ch0($BBID);
    //
    delay(switch_off_delay);
    //
    //Set heater to their stby value: should not depend on band
    HL_heater_proc_fm("1a","stby");
}

//Chopper health check test#2 during open loop, mode
mode HifiManCmd_Chopper_openloop_scan_health_check {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red 
}{
    mois_tmcheck("The instrument can be in Standby I, Standby II or Primary mode in open loop context for this test");
    //It is done after chopper has been switched on in open loop
    mois_spacon("Check that procedure HIFI_Chopper_openloop_set_health_check has been performed previously and analysed as PASS");
    if(prime_or_redundant == "Prime") {
        mois_tmcheck("The instrument must have been switched on with the PRIME side");
    } else {
        mois_tmcheck("The instrument must have been switched on with the REDUNDANT side");
    }
    mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to OPEN");
    mois_tmcheck("Check that parameter HF_DPR_CHSINE_S is set to ON");
    //
    mois_comment("Performing part two of HIFI internal chopper health check");
    StartMode_block_ops();
    //
    mois_step("Perform chopper scan in open loop");
    Chopper_openloop_scan_block_ops(prime_or_redundant);
    //
    StopMode_block_ops();
    mois_spacon("Write down the OBS_ID corresponding to this mode and communicate it to the HIFI ICC");
}

// messages giving gyro-calibration information
procedure GCPMessages {
    int gcp_time = 15; // pointing time at GCP
    int gcp_period = 500; // period for visiting the GCP
    int tend = 0; // final decelleration time as indication for planet
}{
    // Constants hard coded
    int tend_fixed = 0;
    int critical = 0;
    int min_gcp_time = 15;
    int max_gcp_period = 2000;
    // close any previous messages
    message("</p>");
    message("<h2>Gyro-calibration</h2>");
    message("<p>");
    // Actual messages
    if(gcp_time > critical) {
        if(tend > tend_fixed) {
            message("A-posteriori pointing improvement is not possible for " + "solar system objects.");
        } else {
            if(gcp_time >= min_gcp_time && gcp_period <= max_gcp_period) {
                message("A-posteriori relative pointing improvement can be obtained " + "from a gyro-calibration taking " + gcp_time + "s every " + gcp_period + "s.");
            } else {
                message("The AOR is not optimized for gyro-calibration.");
                message("It is not clear whether any a-posteriori relative " + "pointing improvement can be obtained from a " + "gyro-calibration taking " + gcp_time + "s every " + gcp_period + "s.");
            }
        }
    } else {
        message("No a-posteriori pointing improvement possible for this AOR.");
    }
}

// HRS partial configuration with choice of central freq for hr sub-band, block
// Configures the LO and attenuators
block FSW_Response_time_HRSConfig_block_fm HIFI 3689 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["hr","hr"]; //HRS resolution code
    double hr_central_freq = 5.0; //IF freq of HRS hr sub-band in GHz
}{
    //Start_block();
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double hrsH_ATT_U1 = result[1]{0};
    double hrsH_ATT_L1 = result[2]{0};
    double hrsH_ATT_U2 = result[3]{0};
    double hrsH_ATT_L2 = result[4]{0};
    double hrsH_ATT_U3 = result[5]{0};
    double hrsH_ATT_L3 = result[6]{0};
    double hrsH_ATT_U4 = result[7]{0};
    double hrsH_ATT_L4 = result[8]{0};
    double[] hrsH_LO = [hr_central_freq,result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double hrsV_ATT_U1 = result[1]{0};
    double hrsV_ATT_L1 = result[2]{0};
    double hrsV_ATT_U2 = result[3]{0};
    double hrsV_ATT_L2 = result[4]{0};
    double hrsV_ATT_U3 = result[5]{0};
    double hrsV_ATT_L3 = result[6]{0};
    double hrsV_ATT_U4 = result[7]{0};
    double hrsV_ATT_L4 = result[8]{0};
    double[] hrsV_LO = [hr_central_freq,result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_ATT_U1,hrsH_ATT_L1,hrsH_ATT_U2,hrsH_ATT_L2,hrsH_ATT_U3,hrsH_ATT_L3,hrsH_ATT_U4,hrsH_ATT_L4,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
    // 
    //delay(hrs_config_delay);
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsV_ATT_U1,hrsV_ATT_L1,hrsV_ATT_U2,hrsV_ATT_L2,hrsV_ATT_U3,hrsV_ATT_L3,hrsV_ATT_U4,hrsV_ATT_L4,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
    // 
    delay(hrs_config_delay);
}

// FPU Standby with chopper switched on. HBB is also ON  per default, procedure
procedure Band0_chopper_on_proc_fm {
    string band = "0"; // HIFI band
    string chop_loop = "CLOSE"; // Chopper Loop status
}{
    //Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current_on"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    result_d = ConfigurationReader("name_confilfpu",["bias_standby_h","diplexer_standby_h","bias_standby_v","diplexer_standby_v","diplex_h_ctrl_mode","diplex_v_ctrl_mode","chop_cold"],band,0.0);
    //
    double bias_H = result_d[0]{0};
    double diplex_H = result_d[1]{0};
    double bias_V = result_d[2]{0};
    double diplex_V = result_d[3]{0};
    int diplex_h_ctrl_mode = iround(result_d[4]{0});
    int diplex_v_ctrl_mode = iround(result_d[5]{0});
    //
    //Retrieve magnets Magnet are so far at maximum value. Now set to nominal
    double magnetcurrent_H = result_d[1]{0};
    double magnetcurrent_V = result_d[4]{0};
    //
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_standby_h","magnet_standby_v"],band,0.0);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,0.0);
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
}

//////////////////////////////////////////////////////////////////
// HRS complete configuration with maximum attenuation, procedure
// Both polarizations are treated
procedure HRS_standby_proc_ops {
    string band = "0"; // HIFI band
    string[] hrs_mode = ["wb","wb"]; //HRS resolution code
}{
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_ops(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrh_up_ol1_m = a_m_parameter[1];
    int hrh_up_ol1_a = a_m_parameter[0];
    int hrh_up_ol2_m = a_m_parameter[3];
    int hrh_up_ol2_a = a_m_parameter[2];
    int hrh_up_ol3_m = a_m_parameter[5];
    int hrh_up_ol3_a = a_m_parameter[4];
    int hrh_up_ol4_m = a_m_parameter[7];
    int hrh_up_ol4_a = a_m_parameter[6];
    int hrh_down_ol5_m = a_m_parameter[9];
    int hrh_down_ol5_a = a_m_parameter[8];
    int hrh_down_ol6_m = a_m_parameter[11];
    int hrh_down_ol6_a = a_m_parameter[10];
    int hrh_down_ol7_m = a_m_parameter[12];
    //V-polar
    int hrv_up_ol1_m = a_m_parameter[14];
    int hrv_up_ol1_a = a_m_parameter[13];
    int hrv_up_ol2_m = a_m_parameter[16];
    int hrv_up_ol2_a = a_m_parameter[15];
    int hrv_up_ol3_m = a_m_parameter[18];
    int hrv_up_ol3_a = a_m_parameter[17];
    int hrv_up_ol4_m = a_m_parameter[20];
    int hrv_up_ol4_a = a_m_parameter[19];
    int hrv_down_ol5_m = a_m_parameter[22];
    int hrv_down_ol5_a = a_m_parameter[21];
    int hrv_down_ol6_m = a_m_parameter[24];
    int hrv_down_ol6_a = a_m_parameter[23];
    int hrv_down_ol7_m = a_m_parameter[25];
    //Attenuators are fixed
    //H-polar
    double hrh_1u_att = 15.5;
    double hrh_1l_att = 15.5;
    double hrh_2u_att = 15.5;
    double hrh_2l_att = 15.5;
    double hrh_3u_att = 15.5;
    double hrh_3l_att = 15.5;
    double hrh_4u_att = 15.5;
    double hrh_4l_att = 15.5;
    //V-polar    
    double hrv_1u_att = 15.5;
    double hrv_1l_att = 15.5;
    double hrv_2u_att = 15.5;
    double hrv_2l_att = 15.5;
    double hrv_3u_att = 15.5;
    double hrv_3l_att = 15.5;
    double hrv_4u_att = 15.5;
    double hrv_4l_att = 15.5;
    //Configure HRS-H
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrh_1u_att,hrh_1l_att,hrh_2u_att,hrh_2l_att,hrh_3u_att,hrh_3l_att,hrh_4u_att,hrh_4l_att,hrh_up_ol1_m,hrh_up_ol1_a,hrh_up_ol2_m,hrh_up_ol2_a,hrh_up_ol3_m,hrh_up_ol3_a,hrh_up_ol4_m,hrh_up_ol4_a,hrh_down_ol5_m,hrh_down_ol5_a,hrh_down_ol6_m,hrh_down_ol6_a,hrh_down_ol7_m);
    //delay(hrs_config_delay);
    //
    //Configure HRS-V
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrv_1u_att,hrv_1l_att,hrv_2u_att,hrv_2l_att,hrv_3u_att,hrv_3l_att,hrv_4u_att,hrv_4l_att,hrv_up_ol1_m,hrv_up_ol1_a,hrv_up_ol2_m,hrv_up_ol2_a,hrv_up_ol3_m,hrv_up_ol3_a,hrv_up_ol4_m,hrv_up_ol4_a,hrv_down_ol5_m,hrv_down_ol5_a,hrv_down_ol6_m,hrv_down_ol6_a,hrv_down_ol7_m);
    delay(hrs_config_delay);
    //
    //Now Configure blocks
    HRS_config_resol_proc_ops(band,hrs_mode);
    //
    //Check attenuator values
    mois_tmcheck("Check that parameters HRH_1U_ATT, HRH_1L_ATT, HRH_2U_ATT, HRH_2L_ATT, HRH_3U_ATT, HRH_3L_ATT, HRH_4U_ATT and HRH_4L_ATT are set to 15.5");
    mois_tmcheck("Check that parameters HRV_1U_ATT, HRV_1L_ATT, HRV_2U_ATT, HRV_2L_ATT, HRV_3U_ATT, HRV_3L_ATT, HRV_4U_ATT and HRV_4L_ATT are set to 15.5");
    //Check LO locks and values
    mois_tmcheck("Check that parameters HRH_LOCK_LO1_S, HRH_LOCK_LO2_S, HRH_LOCK_LO3_S, HRH_LOCK_LO4_S, HRH_LOCK_LO5_S, HRH_LOCK_LO6_S, and HRH_LOCK_LO7_S are all Locked");
    mois_tmcheck("Check that parameters HRV_LOCK_LO1_S, HRV_LOCK_LO2_S, HRV_LOCK_LO3_S, HRV_LOCK_LO4_S, HRV_LOCK_LO5_S, HRV_LOCK_LO6_S, and HRV_LOCK_LO7_S are all Locked");
    Check_HRS_LO_proc_ops([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
}

//Chopper rotation procedure. Reduced version without overshooting treatment
// Always one step
procedure RotateChopper {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    string chop_target = "chop_cold"; //Targetted chopper position
}{
    {bool,double,double} chopparms = GetChopVoltages(band,lo_freq,chop_target,chop_target);
    bool isPrime = chopparms{0};
    // Call command
    if(isPrime) {
        Hifi_HIFI_P_Chopper_Rot($BBID,chopparms{1});
    } else {
        Hifi_HIFI_R_Chopper_Rot($BBID,chopparms{1});
    }
    // No delays should be required here
}

//Procedure to store currently tuned frequency, procedure
//Only applicable to non-FSW obs.
procedure HIFI_HL_store_tm_only_proc_fm {
}{
    Hifi_HIFI_HL_store_tm($BBID);
    delay(1);
}

// General version used in most observingmodes
procedure LoadMeasurement {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double lo_freq = 978200.0; // LO frequency
    double deltanu = 1.0; // minimum effective resolution of the calibrated data
    int data_time = 4; // time between subsequent data readouts
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
}{
    // Call generic version with fixed parameters
    SScanLoadMeasurement(band,lo_freq,lo_freq,true,deltanu,data_time,backendreadoutparms);
}

//Set to rescue from switched off
mode HifiManCmd_HIFI_SwitchedOff_to_Rescue {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    Mode_status_check_switched_off();
    mois_comment("Switching to rescue mode");
    mois_step("Power ON the ICU - start up the BSW");
    string icu_subsys = "ICU_Prime";
    if(prime_or_redundant == "Red") {
        icu_subsys = "ICU_Red";
    }
    PDU_switch_on_block_ops(icu_subsys);
    Mode_status_check_rescue("normal");
}

{string,double,double}[] procedure HifiMappingModeLoadChopOTFNoRefSequencerInit {
    string modeName = "load-raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period defines number of lines between two loads
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(0.3 * allan_time_lores),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // n_switch limited by load_interval - 2 lines should be possible
    int n_switch_on_guess = load_interval / (4 * npoints * data_time_guess);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // Contruct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)}];

    return retvalues;
}

//Diplexer FSW investigation: phase-block
procedure Dip_FSW_B_phase {
    string band = "3a" in ["3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI band
    bool retune = true; //whether the diplexer is adjusted between frequencies or not
    double lo_freq2 = 810.0;
    double lo_freq_ref = 810.0;
    int[] res = [4,1];
    string backend = "both";
    string polarization = "H" in ["H","V"]; //The polarization on which the test is done
    bool modulate = true; //whether we change FSW register and DPACT
}{
    //Integrate at FSW1
    if(modulate) {
        Activate_FSW_register_block_fm("FSW2");
        if(retune) {
            Set_Single_Diplexer_current_block_fm(band,lo_freq2,polarization);
        } else {
            Set_Single_Diplexer_current_block_fm(band,lo_freq_ref,polarization);
        }
    } else {
        //Hifi_HIFI_noop();
    }
    Spectro_total_power_AOTLike_block_fm(band,res,backend);
    //Add 2sec for investigation of SPR-2404
    delay(2);
}

//////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the observing mode
{double,double,double,double,double} procedure SScanChopNoRef_noisecomputer {
    string band = "4a"; // HIFI band
    double reffreq = 978300.0; // Reference LO frequency in scan center
    int nfreq = 4; // Number of frequency points per IF
    bool dsb = true; // Both sidebands covered
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    int n_cycles = 1; // Number of map coverages
    bool fs = false; // whether frequency switch used
    double tscan = 60.0; // Total average duration of one scan
    double tdead = 10.0; // Average dead time in one slew
}{
    // spectral scans always use the full bandwidth for reference
    bool oneGHzReference = false;
    // Call position switch noise computer
    {double,double,double,double,double} noisevalues = PositionSwitch_noisecomputer(band,reffreq,eff_resolution,oneGHzReference,n_cycles,tscan,tdead);
    // Correct for multiple frequencies and signal in both phases in case of FSW
    if(fs) {
        double multiplier = sqrt(0.5 / double(nfreq));
    } else {
        multiplier = sqrt(1.0 / double(nfreq));
    }
    noisevalues{0} = noisevalues{0} * multiplier;
    noisevalues{1} = noisevalues{1} * multiplier;
    // Check for double sideband coverage
    if(dsb) {
        // Combine LSB-USB noise
        // In spectral scans we have only a combined noise temperature for both
        // sidebands, so that the USB/LSB separation is not used
        double[] gssb = InterpolateGssb(band,reffreq);
        double usbnoise_lores = noisevalues{0} / sqrt(1.0 + gssb[1] / gssb[0] * (gssb[1] / gssb[0]));
        double usbnoise_hires = noisevalues{1} / sqrt(1.0 + gssb[1] / gssb[0] * (gssb[1] / gssb[0]));
        double lsbnoise_lores = usbnoise_lores;
        double lsbnoise_hires = usbnoise_hires;
    } else {
        // Get single sideband noise equivalent
        usbnoise_lores = noisevalues{0};
        usbnoise_hires = noisevalues{1};
        lsbnoise_lores = noisevalues{2};
        lsbnoise_hires = noisevalues{3};
    }
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noisevalues{4}};
}

//Switch off upconverter, block
//It assumes that mixer and chopper are also to be switched off
block Upconverter_switch_off_block_fm HIFI 3645 {
}{
    Start_block();
    Hifi_HIFI_Configure_FCU_Power($BBID,"OFF","OFF","OFF","OFF","OFF");
    delay(1);
}

//  LCU3b configuration into SAFE mode, procedure
procedure LCU3b_config_safe_proc_fm {
    string band = "3b"; // HIFI band
    double lo_freq = 900.0 in [852.0,953.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

// Get dead time for chopper motion
double procedure GetSkyChopDeadTime {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] dead = CalibrationReader("chop_deadtime",["skychop"],band,lo_freq);

    return dead[0];
}

// Magnet current scan, slow, procedure
// IF power as function of magnet current
procedure Magnet_scan_slow_proc {
    string band = "1a"; // HIFI band		//Setting file
    double magnet_current_min_h = -10.0; //minimum magnet current H
    double magnet_current_max_h = 15.0; //maximum magnet current H
    double magnet_current_min_v = -10.0; //minimum magnet current V
    double magnet_current_max_v = 15.0; //maximum magnet current V
    int n_steps = 100; //number of steps
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3
    int integ_time = 4; //Total integration time in sec.: at least 2sec !  
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    double lo_freq = 522.0; //LO frequency
    int tune_target_magnet = 40 in [10,85]; //Target WBS illumination percentage during magnet tuning
    double shapiro_bias = 1.8; //Shapiro Mixer bias, same used for both polarization 
}{
    //
    //WBS calibration
    //Configure backends to max. attenuation for magnet scan
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
    }
    //
    //Configure spectrometers integration
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    Magnet_scan_slow_fm(band,magnet_current_min_h,magnet_current_max_h,magnet_current_min_v,magnet_current_max_v,n_steps,integ_time,lo_freq,backend,tune_target_magnet,shapiro_bias);
    //Back to nominal values
    {double,string}[] result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
    //First set magnet to maximum to avoid hysteresis
    double magnetcurrent_max_h = result[0]{0};
    double magnetcurrent_max_v = result[1]{0};
    Set_Magnet_current_block_fm(magnetcurrent_max_h,magnetcurrent_max_v);
    //
    //Nominal values
    result = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v","norm_bias_h","norm_bias_v"],band,lo_freq);
    Set_Magnet_current_block_fm(result[0]{0},result[1]{0});
    //Also set bias voltages back to nominal values
    Mixerbias_block_fm(result[2]{0},result[3]{0});
}

////////////////////////////////////
// Fast chop DBS raster observing mode - Engineering version with half throw
// 
// The timing is defined as WBS timing, the HRS takes more data during
// the WBS read out, but this is ignored in the computations here.
//
// Return time and noise levels
{int,double,double,double,double,double} obs HifiEngHalfThrowFastDBSRaster {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,100]; // Number of rows in the map
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the raster line
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Engineering - DBS Raster Map halfThrow fastChop",{data_time,0,n_int_on,n_switch_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = FastDBSRaster_pre_timing(nlines,npoints,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    // Check for NoddingInRaster or NoddingOfRaster
    int scansize = pre_timing{10};
    if(scansize > 1) {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,double,double,int,int,int,int,int} tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"half",pre_timing,n_cycles);
        // Dummy call to spacecraft command
        int[] telescopetimes = nodding_of_raster_pointing(false,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double,int,int,int,double,double,int,int,int,int} tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"half",pre_timing,n_cycles);
        telescopetimes = nodding_raster_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSRaster_post_timing(pre_timing,telescopetimes,nlines,npoints,n_switch_on,n_cycles,load_interval,true);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    if(scansize > 1) {
        tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"half",post_timing{1},n_cycles);
        // Call telescope command
        telescopetimes = nodding_of_raster_pointing(true,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"half",post_timing{1},n_cycles);
        telescopetimes = nodding_raster_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        HalfFastDBSRaster_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,false);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastDBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints,n_cycles,n_seq * n_int_on * imax(n_load,1),tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//
// Diplexer scan very fast, block.
// Mixer current as function of diplexer current.
// Uses the new OBS TC allowing much faster scan.
block Scan_diplexer_block_fm HIFI 3254 {
    string band = "3a"; // HIFI band
    double diplexer_current_min_h = -2.24; //minimum diplexer current H
    double diplexer_current_min_v = -2.24; //minimum diplexer current V
    double diplexer_current_step = 0.1; //maximum diplexer current V
    int n_steps = 100; //number of steps
    double stepTime = 0.1; //Step time in seconds
}{
    //Start_block();
    //double stepTime = 0.07;	//Should be in a config file eventually
    //Check how many TCs need to be sent
    int max_step = 61;
    int nloop = iceil(double(n_steps) / double(max_step));
    //Compute number of step for last interation
    int last_n_steps = n_steps - (nloop - 1) * max_step;
    int dipscan_delay = 0;
    //
    //Preset to first value and wait 1sec (for possible overshoot)
    Set_Diplexer_current_proc_fm(diplexer_current_min_h,diplexer_current_min_v);
    //Send command
    for(int i = 1 .. nloop) {
        n_steps = max_step;
        diplexer_current_min_h = diplexer_current_min_h + double((i - 1) * max_step) * diplexer_current_step;
        diplexer_current_min_v = diplexer_current_min_v + double((i - 1) * max_step) * diplexer_current_step;
        if(i == nloop) {
            n_steps = last_n_steps;
        }
        Hifi_HIFI_scan_diplexer($BBID,n_steps,stepTime,diplexer_current_min_h,diplexer_current_min_v,diplexer_current_step);
        //Compute delay
        dipscan_delay = iceil(1.0 + double(n_steps) * (stepTime + 0.03));
        delay(dipscan_delay + 1);
    }
}

//Magnet tune fine, procedure
procedure Magnet_tune_fine {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Integration time
    double lo_freq = 522.0; //LO frequency
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    Magnet_scan_fine_fm(band,integ_time,lo_freq,backend);
}

///////////////////////////////////////////////////////////////////
// Procedure to compute detailed post timing for the version of the
// load-chop and frequency-switch modes with baseline measurement
// 
{int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},int,bool,double,double} procedure DoubleChop_post_timing {
    {int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} pre_timing = {16,16,16,16,21,11,1800,32,2,2,0,0,false,false,50,0}; // pre_timing parameter list
    int[] telescopetimes = [300,180,20,1,21,0];
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF calibration cycles
}{
    // Get all values from the pre_timing section
    int on_inttime = pre_timing{0};
    int off_inttime = pre_timing{1};
    int on_pointing = pre_timing{2};
    int off_pointing = pre_timing{3};
    int loadlength = pre_timing{4};
    int jitterdead = pre_timing{5};
    int load_spacing = pre_timing{6};
    int n_loadinterval = pre_timing{7};
    int n_per_on = pre_timing{8};
    int n_per_off = pre_timing{9};
    int n_load_on = pre_timing{10};
    int n_load_off = pre_timing{11};
    bool end_load_on = pre_timing{12};
    bool end_load_off = pre_timing{13};
    int initlength = pre_timing{14};
    int dangling = pre_timing{15};
    // Use all values from the telescope section
    int telinit = telescopetimes[1];
    // Initial slew time
    int slewtime = telescopetimes[2];
    // Slew time to OFF
    int pointwaittime = telescopetimes[3];
    // Idle time between two phases
    int longslew = telescopetimes[4];
    // Actual slew time for load slew
    int tend = telescopetimes[5];
    // Final deceleration time
    // If load is performed between the cycles use pointwaittime for load
    int halfloadlength = (loadlength - jitterdead + 1) / 2;
    int effhalfloadlength = (loadlength - jitterdead - pointwaittime + 1) / 2;
    if(end_load_on) {
        on_pointing = on_pointing - (halfloadlength - effhalfloadlength);
        int shiftlength_on = effhalfloadlength;
    } else {
        shiftlength_on = 0;
    }
    if(end_load_off) {
        off_pointing = off_pointing - (halfloadlength - effhalfloadlength);
        int shiftlength_off = effhalfloadlength;
    } else {
        shiftlength_off = 0;
    }
    // treat remaining pointwaittime like an additional slew dead time in cycles
    slewtime = slewtime + pointwaittime;
    longslew = longslew + pointwaittime;
    // Now we can compute the true scan time
    int scan_time = on_pointing + off_pointing + slewtime;
    // Finally I can compute the load interval
    n_loadinterval = imax((load_spacing + slewtime) / scan_time,1);
    // Exception handling for very uneven phases
    if(end_load_on || end_load_off) {
        n_loadinterval = 1;
    }
    // Variables for the noise computer
    // Compute duration of measurement and average scan length
    // Compute total dead time in one pointing cycle including load overhead
    int scan_time_long = on_pointing + off_pointing + longslew;
    int n_long = n_cycles / n_loadinterval;
    // Determine need for final load measurement
    double rest = double(n_cycles % n_loadinterval) + 0.5;
    bool final_load = rest > 0.5001 * double(n_loadinterval);
    int looplength = (n_cycles - n_long) * scan_time + n_long * scan_time_long;
    double tscan = double(looplength) / double(n_cycles);
    // Get pointing dead time, instrument dead time is added later
    double tdead = tscan - double(off_inttime + on_inttime);
    int initshiftlength = shiftlength_off;
    // Check the last pointing cycle, repeated on the telescope procedure
    if(n_cycles % 2 == 0) {
        int lastshiftlength = shiftlength_off;
    } else {
        lastshiftlength = shiftlength_on;
    }
    // Add dangling load time
    if(lastshiftlength > 0) {
        dangling = loadlength - lastshiftlength;
    }
    if(final_load) {
        dangling = loadlength;
    }
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    // Compute total duration
    initlength = initlength - initshiftlength;
    // The initial time is no longer contained in the total time  
    // Compute total duration, remove pointwaittime for last slew
    int totaltime = looplength + dangling - pointwaittime + tend;
    // show gyro-propagation messages
    GCPMessages(off_pointing,2 * scan_time_long,tend);
    // Return all the times needed in the telescope and instrument modules

    return {totaltime,{on_inttime,off_inttime,on_pointing,off_pointing,loadlength,jitterdead,load_spacing,n_loadinterval,n_per_on,n_per_off,n_load_on,n_load_off,end_load_on,end_load_off,initlength,dangling},initshiftlength,final_load,tscan,tdead};
}

//General LO configuration command
//  Uses SFT approach with safe call to 3b BUT combined TM page dump
block HIFI_Configure_LCU_block_spur HIFI 3978 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    int freq_nx = 0; // HL_freq_nx
    int lsu_main = 0; // HL_LSU_main
    int lsu_offset = 0; // HL_LSU_offset
    int d2_step = 1; // HL_D2_step
    double plevel_v = 0.0;
    double m1_v = 9.0;
    double m2_v = -2.0;
    double m3_v = 0.0;
    double gate1_v = -2.5;
    double gate2_v = -2.5;
    double drain1_v = 2.8;
    string curlim1_v = "1.4";
    double drain2_v = 2.6;
    string curlim2_v = "1.4";
    int macro_checksum = 0; // HL_macro_checksum
    int config_lo_delay = 6;
}{
    //Check that Vd2 is within the blue limits
    drain2_v = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v);
    //
    //Start_block(); 
    //
    //Execute configuration
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_safe_LCU_ch1a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_safe_LCU_ch1b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_safe_LCU_ch2a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_safe_LCU_ch2b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_safe_LCU_ch3a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_safe_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_safe_LCU_ch4a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_safe_LCU_ch4b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
    delay(config_lo_delay);
    //
    //Store settings into available register
    //HIFI_HL_store_tm_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

/////////////////////////////////////////////////////////
// WBS configuration with maximum attenuation, block
// Lasers set up as in config file
block WBS_config_max_att_block_fm HIFI 3638 {
    string band = "1a"; // HIFI band
}{
    //Start_block();
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = result_d[0]{1};
    string hwh_laser2_s = result_d[1]{1};
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = 7;
    int hwh_att_band3 = 7;
    int hwh_att_band2 = 7;
    int hwh_att_band1 = 7;
    int hwh_att_in = 15;
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //delay(wbs_config_delay);
    //V-Polarization
    //Get configuration parameters
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = result_d[0]{1};
    string hwv_laser2_s = result_d[1]{1};
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = 7;
    int hwv_att_band3 = 7;
    int hwv_att_band2 = 7;
    int hwv_att_band1 = 7;
    int hwv_att_in = 15;
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    //Wait delay to allow all setting to be configured
    delay(wbs_config_delay);
}

//Force boot, procedure: NOT LONGER USED, USE BLOCK INSTEAD
procedure HIFI_force_boot_proc {
    int partition_ID = 0; //0 if forceboot_default. Partition ID in case it should be used. 
}{
    if(partition_ID == 0) {
        Hifi_HIFI_force_bootdefault();
    } else {
        Hifi_HIFI_force_bootpartition(partition_ID);
    }
    //Increase delay - SPR-1354
    delay(5);
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double} procedure OTFmap_deadtimes {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int n_supersample = 1; // Supersamplingfactor
    int n_linesperscan = 1; // Number of lines between two OFFs
    int n_intoff = 3; // Number of data dumps for the OFF integration time
    int n_pp = 10; // Number of data dumps per line
    double tdead = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Dead time in OFF
    {double,double} tinst = GetInstDeadSlowChop(data_time,n_intoff,"tp",band,lo_freq,backendreadoutparms);
    // dead time within OFF
    double tdeadint = double(data_time * n_intoff) - tinst{0};
    // total dead time from OFF
    double tdead_tot = tdead + tdeadint;
    double tintoff = tinst{0};
    // Dead time in one line
    tinst = GetInstDeadSlowChop(data_time,n_pp,"tp",band,lo_freq,backendreadoutparms);
    // Dead time for each line
    tdeadint = double(data_time * n_pp) - tinst{0};
    tdead_tot = tdead_tot + double(n_linesperscan) * tdeadint;
    double tintpoint = tinst{0} / double(n_pp) * double(n_supersample);
    // Return total dead time and actual integration times

    return {tdead_tot,tintpoint,tintoff};
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure LoadChopNoRef_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval limited by the data rates
    int n_per_on = 2; // number of half load-sky-sky-load cycles on ON
    int n_load_on = 0; // additional load measurements in ON pointing phase
    bool end_load_on = false; // Need for load after ON pointing phase
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,0]; // Timing of observation from telescope
    int loadlength = 21; // Load duration
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // ON integration
            HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i1 = 1 .. n_load_on) {
                HIFILoadChopOnIntegration(data_time,n_per_on,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFILoadChopOnIntegration(data_time,n_per_on,band,lo_freq,rates);
        }
        if(state[0] == 5) {
            delay(readoutdead);
            if(end_load_on) {
                // Perform final load measurement 
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            HIFICloseObs();
        }
    }
}

// Initialisation of FPU, block with only H-MSA in use
// It is only for cold context
block Init_MSA_H_fm HIFI 3207 {
    string band = "1a";
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],"0",0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current_on"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,0.0);
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //In case of band 6 or 7, bias have been set to 4mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    //Magnet are so far at maximum value. Now set to nominal
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
        Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
        delay(1);
    }
    //
    Hifi_HIFI_non_periodic_hk_FCU();
}

/////////////////////////////////////////////////////////////////
// Get limiting frequencies 
{double,double} procedure GetBandLimits {
    string band = "4a"; // HIFI band
}{
    // read master file
    string calibfile = slookup("frequencystep_masterfile",band,"tablefile");
    double[] allfpoints = dcolumn(calibfile,"stepfrequency");
    // get table size
    int iindex1 = length(allfpoints);
    double firstlo = allfpoints[1];
    double lastlo = allfpoints[iindex1 - 2];

    return {firstlo,lastlo};
}

////////////////////////////////////
// Fast chop DBS raster observing mode
// 
// The timing is defined as WBS timing, the HRS takes more data during
// the WBS read out, but this is ignored in the computations here.
//
// Combination of four modules implementing the new structure 
//
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcFastDBSRaster {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,100]; // Number of rows in the map
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the raster line
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Mapping - DBS Raster Map fastChop",{data_time,0,n_switch_on,n_int_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = FastDBSRaster_pre_timing(nlines,npoints,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    // Check for NoddingInRaster or NoddingOfRaster
    int scansize = pre_timing{10};
    if(scansize > 1) {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,double,double,int,int,int,int,int} tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        // Dummy call to spacecraft command
        int[] telescopetimes = nodding_of_raster_pointing(false,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double,int,int,int,double,double,int,int,int,int} tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        telescopetimes = nodding_raster_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSRaster_post_timing(pre_timing,telescopetimes,nlines,npoints,n_switch_on,n_cycles,load_interval,true);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    if(scansize > 1) {
        tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        // Call telescope command
        telescopetimes = nodding_of_raster_pointing(true,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        telescopetimes = nodding_raster_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FastDBSRaster_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,false);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastDBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints,n_cycles,n_seq * n_int_on * imax(n_load,1),tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Configuration for fast-chop integration
int[] block HIFIConfigureFastChopIntegration HIFI 6040 {
    int data_time = 4; // Integration time between two data readouts
    int n_int = 20; // number chop cycles to integrate in ICU before transfer
    int n_seq = 1; // Number of continuous data transfer cycles
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used, channel windows}
}{
    // Call procedure doing the work
    {int,int} fchop = FastConfigureSpectroscopy(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
    // Return data rates for command

    return [fchop{0},fchop{1}];
}

/////////////////////////////////////////////////////////////////
// get reference frequency, resolution, redundancy 
{double,int,double} procedure GetFReference {
    string band = "4a"; // HIFI band
    double lo_freq1 = 978200.0 in [480000.0,1950000.0]; // LO frequency
    double lo_freq2 = 979600.0 in [480000.0,1950000.0]; // LO frequency
}{
    // first step: read master file
    double referencefreq = ComputeReferenceFreq(band,lo_freq1,lo_freq2);
    int redundancy = ilookup("frequencystep_masterfile",band,"redundancy");
    double stdstep = dlookup("frequencystep_masterfile",band,"stdstep");

    return {referencefreq,redundancy,stdstep};
}

//Contingency for LOU temp FDIR modification
mode HifiManCmd_LOU_FDIR_enable {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    mois_comment("Procedure to enable and modify FDIR limits for LOU operational temperatures");
    //StartMode_block_ops(); 
    //
    mois_step("Set new FDIR limits");
    Set_LO_FDIR_temperatures_block_mois();
    //
    StopMode_block_ops();
    // -> to issue last obsd/bbid
}

//Chopper rotation block. It takes into account
//overshoot risk and performs the rotation in
//2 steps if the targetted positions are either of the end stops
block Chopper_Rotation_block_fm HIFI 3646 {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string chop_current_position = "chop_hot_ang"; //Current chopper position
    string chop_target_position = "chop_cold_ang"; //Targetted chopper position
}{
    Start_block();
    //Retrieve angles of corresponding positions
    {double,string}[] result_d = ConfigurationReader("name_chopper",[chop_current_position,chop_target_position,"chop_endstopright_ang","chop_endstopleft_ang","overshoot"],band,0.0);
    double chop_current_angle = result_d[0]{0};
    double chop_target_angle = result_d[1]{0};
    double chop_endstopright_angle = result_d[2]{0};
    double chop_endstopleft_angle = result_d[3]{0};
    double overshoot = result_d[4]{0};
    string chop_target_name = result_d[1]{1};
    string chop_current_name = result_d[0]{1};
    int step = 1;
    //
    //Check whether the rotation may reach either of the end stops, i.e.
    //go beyond either the HBB or M3_left
    ///// We suppose here overshoot to be 0, so the 2 steps only occur when targetting
    ///// the end stops strictly.
    overshoot = 0.0;
    double total_angle = abs(chop_target_angle - chop_current_angle) * (1.0 + overshoot);
    //
    //The endstop that one may hit depends on the rotating direction
    //Case were endstop is the left one
    double angle_to_endstop = abs(chop_endstopleft_angle - chop_current_angle);
    if(chop_target_angle > chop_current_angle) {
        //then end stop is the right one
        angle_to_endstop = abs(chop_endstopright_angle - chop_current_angle);
    }
    //debug_print(total_angle);
    //debug_print(angle_to_endstop);
    if(total_angle >= angle_to_endstop) {
        message("Chopper expected to hit the endstop. Rotation done in two steps");
        step = 2;
    }
    //If we have two steps necessary, the middle position between current and
    //targetted position is used.
    result_d = ConfigurationReader("name_confilfpu",[chop_target_name,chop_current_name],band,0.0);
    double chop = result_d[0]{0};
    double chop_intermediate = (result_d[0]{0} + result_d[1]{0}) / 2.0;
    //
    chop = Check_Chopper_Prime_Redundant(chop);
    if(step == 1) {
        HIFI_CPR_Chopper_Rot_proc_fm(chop);
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent voltage
        delay(1);
    }
    if(step == 2) {
        chop_intermediate = Check_Chopper_Prime_Redundant(chop_intermediate);
        HIFI_CPR_Chopper_Rot_proc_fm(chop_intermediate);
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent voltage
        delay(1);
        HIFI_CPR_Chopper_Rot_proc_fm(chop);
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent voltage
        delay(1);
    }
}

/////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing for the mode
// 
{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} procedure PositionSwitch_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,5]; // data dump interval limited by the data rates
    int n_int = 3 in [2,1800]; // number of data dumps for integration per phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    // Compute parameters for the instrument timing
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    int inttime = n_int * data_time;
    // Resulting integer integration time
    int pointing = inttime + jitterdead;
    // Pointing time
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    int halfloadlength = (loadlength - jitterdead + 1) / 2;
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,2 * inttime);
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,false);
    }
    initlength = initlength + loadlength;
    // Compute the load period
    // First estimate of the load interval
    int n_loadinterval = imax(load_interval / (2 * pointing),1);
    // Dangling load not known yet at this point
    bool final_load = false;
    int dangling = readoutdead;
    // pseudo parameters which are notneeded here, but used for a 
    // unified treatment of all modes using the same pointing command
    int n_seq = 1;
    int n_load = 0;
    // Return all the times needed for telescope call and post_timing processing

    return {inttime,inttime,pointing,pointing,loadlength,halfloadlength,load_spacing,n_loadinterval,n_seq,n_seq,n_load,n_load,final_load,final_load,initlength,dangling};
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Testmodes for Functional test of WBS FM
//
// DT - 21/09/04: first draft for QM
// DT - 04/11/04: added new modes
//	19/07/05: Updated for FM
//	09/12/05: Updated after WBS FM delivery. 
//		  Laser2 is the default laser for ILT.
//	22/01/07: Laser1 is the default laser for FM ILT.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Modes: see fm_testmodes.cus
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Associated blocks
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Special COMB FT for WBS, procedure
// Follows procedure requested after COMB problem discovered on WBS-V
procedure FT_COMB_proc_fm {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON  
}{
    //Allow fast HK readout
    HKrate(1.0);
    //
    int integ_time = 2;
    //Total integration time in sec.
    int[] res = Configure_Spectrometer_proc_fm(band,integ_time,["wb1","wb1"],"wbs");
    //Scan all attenuators with COMB ON
    FT_WBS_att_overall_COMB_fm(band,integ_time,laser_H,laser_V,"wbs");
    FT_WBS_att_individual_COMB_fm(band,integ_time,laser_H,laser_V,"wbs");
    //
    //Att. at 7/7/7/7/7
    WBS_config_w_laser_and_att_block_fm(band,laser_H,laser_V,[7,7,7,7,7],[7,7,7,7,7]);
    //Spectra with COMB ON - various integration times
    res = Configure_Spectrometer_proc_fm(band,2,["wb1","wb1"],"wbs");
    Spectro_total_power_block_fm(band,res,"wbs");
    res = Configure_Spectrometer_proc_fm(band,10,["wb1","wb1"],"wbs");
    Spectro_total_power_block_fm(band,res,"wbs");
    res = Configure_Spectrometer_proc_fm(band,20,["wb1","wb1"],"wbs");
    Spectro_total_power_block_fm(band,res,"wbs");
    res = Configure_Spectrometer_proc_fm(band,30,["wb1","wb1"],"wbs");
    Spectro_total_power_block_fm(band,res,"wbs");
    //Switch off zero and comb after the above
    Switch_zero_comb_block_fm("OFF");
    //Back to slow HK readout
    HKrate(0.25);
}

/////////////////////////////////////////////////////////////////
// Get all frequency points in interval
double[] procedure GetFScanPoints {
    string band = "4a"; // HIFI band
    int firstindex = 1; // Index of first frequency point
    int lastindex = 2; // Index of last frequency point
    int increment = 1; // Index increment
}{
    // first step: read master file
    string calibfile = slookup("frequencystep_masterfile",band,"tablefile");
    double[] allfpoints = dcolumn(calibfile,"lo_frequency");
    // Initialize field
    int nstep = (lastindex - firstindex + 2 * increment - 1) / increment;
    double[] fpoints = [];
    // Loop for reading
    for(int i = 0 .. nstep - 1) {
        int counter = firstindex + i * increment;
        fpoints[i] = allfpoints[counter];
    }

    return fpoints;
}

//Tune HIFI at frequency of interest for 2 frequencies (FSW)
procedure HIFITuneFsw {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq_1 = 978200.0; //LO frequency for FSW1 phase
    double lo_freq_2 = 978300.0; //LO frequency for FSW2 phase
    bool hrs1used = true; // HRS1 parameter =used
    bool hrs2used = true; // HRS2 parameter
    bool wbs1used = true; // WBS1 parameter =used
    bool wbs2used = true; // WBS2 parameter
    string target_name = "normal"; // Name of target level
}{
    //
    //LO power tuning: could use either H or V polar
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq_1);
    double x = result[0]{0};
    string tuningbackend = "H";
    if(iround(x) == 2) {
        tuningbackend = "V";
    } else {
        tuningbackend = "H";
    }
    // All tuning for first frequency, and store in FSW1 register
    double lo_freq_setting = 0.5 * (lo_freq_1 / 1000.0 + lo_freq_2 / 1000.0);
    LO_tuning_block_aot(band,lo_freq_1 / 1000.0,lo_freq_setting,tuningbackend,true,true,true);
    //
    //Magnet tuning: could use either HRS or WBS. Not done for bands1,2,6,7 (SCR-2380)
    if(band == "3a" || band == "3b" || band == "4a" || band == "4b" || band == "5a" || band == "5b") {
        // Currently only the HRS is used
        string magnettuningbackend = "HRS";
        Magnet_tuning_block_aot(band,lo_freq_1 / 1000.0,magnettuningbackend);
    }
    //
    //Spectrometer attenuator tuning on HBB
    if(wbs1used || wbs2used) {
        WBS_attenuators_block(band,lo_freq_1 / 1000.0,target_name,false);
    }
    if(hrs1used || hrs2used) {
        HRS_tune_block_aot(band);
    }
    // Second frequency setup, and stored in FSW2 register
    LO_tuning_block_aot(band,lo_freq_2 / 1000.0,lo_freq_setting,tuningbackend,false,true,true);
    //
}

////////////////////////////////////
// OTF load-chop observing mode
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcLoadChopOTF {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    bool refSelected = true; // Dummy parameter required by HSPOT
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints = 10 in [1,720]; // Number of data dumps per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Mapping - OTF Map Load Chop Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,n_linesperscan,0,0,n_cycles,load_interval});
    // Auxiliary routine for API parameter correction
    {double,double,int} mapused = ValidMapSize(band,lo_freq,lineDistance,nlines,stepsize,npoints,2 * data_time * n_switch_on);
    double line_used = mapused{0};
    double scanvelocity = mapused{1};
    int npoints_used = mapused{2};
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int} pre_timing = OTFLoadChop_pre_timing(nlines,npoints_used,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_linesperscan,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,double,double,int,int,int,int,int} tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,pre_timing);
    // Dummy call to spacecraft command
    int[] telescopetimes = line_scan_with_off_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int},double,double} post_timing = OTFmap_post_timing(pre_timing,telescopetimes,data_time,n_linesperscan,n_cycles,load_interval);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,post_timing{1});
    // Call telescope command
    telescopetimes = line_scan_with_off_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int n_pp = post_timing{1}{0};
    int n_scans = post_timing{1}{1};
    int off_inttime = post_timing{1}{2};
    int loadlength = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{5};
    double tscan = post_timing{2};
    double tdead = post_timing{3};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        OTFLoadChop_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,npoints_used * n_switch_on,n_switch_off,nlines * n_cycles,n_linesperscan,n_loadinterval,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = OTFDoubleChop_deadtimes("lchop",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_linesperscan,n_pp,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = OTFLoadChop_noisecomputer(band,lo_freq,effResolution,oneGHzReference,nlines,data_time,n_switch_on,n_linesperscan,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    OTFDoubleChop_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints_used,n_switch_on,n_switch_off,n_scans,n_cycles,false,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Compute the length of an angular vector, derived from AngularDistance
double procedure AngleVectorLength {
    {double,double} vector = {0.0,0.0}; // vector
}{
    double pideg = 3.14159265 / 180.0;
    double dist = acos(cos(vector{0} * pideg) * cos(vector{1} * pideg)) / pideg;

    return dist;
}

// Switch HIFI off, mode
// Assumed to be in standby I when starting this mode
//
mode HifiManCmd_HIFI_global_switch_off_ops {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
    string chopper_loop = "OPEN" in ["OPEN","CLOSE"]; //chopper loop status
}{
    Mode_status_check_standby_I(chopper_loop,"down",prime_or_redundant);
    mois_comment("HIFI global switch OFF: successively switch OFF subsystems");
    StartMode_block_ops();
    HIFI_global_switch_off_proc_ops(prime_or_redundant);
    //from moc_1.2: use proc instead of block
    //Here, HIFI is idle: the switch back to obsid = 0 is done just before ICU switched off
    //StopMode_block_ops () ;
    Mode_status_check_switched_off();
}

// Spectrometer configuration for total power in peakup, procedure
// Adds the possibility to blank a polarization
int[] procedure Configure_Spectrometer_peakup_proc_fm {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5,wb6,wb7,wb8
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string mixer_polarization = "H" in ["H","V"]; //mixer polarization to be used 
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Blank out unused polarization
    if(backend == "wbs") {
        if(mixer_polarization == "H") {
            backendreadoutparms{3}{0} = false;
        } else {
            backendreadoutparms{2}{0} = false;
        }
    }
    if(backend == "hrs") {
        if(mixer_polarization == "H") {
            backendreadoutparms{1}{0} = false;
        } else {
            backendreadoutparms{0}{0} = false;
        }
    }
    //
    //Compute data_time and n_switch using the wrapper
    int[] res = ConfigSlowChop(integ_time,"tp",band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_switch = res[1];
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS. 
    // The deadtimes output is not used at ILT level.
    {double,double} dtimes = ConfigSpectroscopySlowChop_IST(data_time,n_switch,"tp",band,0.0,backendreadoutparms,true);
    //

    return res;
}

//Stopmode, block
block StopMode_block_ops HIFI 7923 {
}{
    {double,string}[] result = ConfigurationReader("name_lastobsid",["last_obsid_Ops_Manual"],"0",0.0);
    mois_comment("Switch to obsid number applicable between observations");
    Hifi_HIFI_Set_OBS_ID(0,iround(result[0]{0}));
    //mois_tmcheck("Check that parameter OBS_ID_per_hk has become " + iround(result[0]{0}));
    delay(1);
}

//HIFI-COP-X-IF-FBk-Dip
procedure IF_FBk_Dip_COP_proc_ops {
    string band = "3a" in ["3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 807.0; //LO frequency
    string[] hrs_mode = ["wb1","wb1"];
    int integ_time = 600;
    string backend = "both";
}{
    //Switch-off LO
    LCU_switch_off_block_fm();
    //
    //Take largest excursion
    string chop1 = "chop_M3left";
    string chop2 = "chop_hot";
    //Get voltages
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",[chop1,chop2],band,0.0);
    int[] res = [0,0];
    //
    Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
    //Use high biases
    result_d = ConfigurationReader("name_confilfpu",["bias_high_resistive_h","bias_high_resistive_v"],band,lo_freq);
    Mixerbias_block_fm(result_d[0]{0},result_d[1]{0});
    WBS_calib_fm(band);
    WBS_tune_proc_fm(band);
    HRS_config_block_fm(band,hrs_mode);
    HRS_tune_block_fm(band);
    //
    //Diplexer settings considered
    int total = 3;
    double[] dipl_curr = [-2.24,0.0,2.24];
    result_d = ConfigurationReader("name_confilfpu",[chop1,chop2],band,0.0);
    res = Configure_Spectrometer_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    //Loop on diplexer settings
    for(int i = 0 .. total - 1) {
        //
        Set_Diplexer_current_block_fm(dipl_curr[i],dipl_curr[i]);
        Spectro_slow_chop_block_fm(band,[result_d[0]{0},result_d[1]{0}],[integ_time * 2,1],backend);
    }
    // 
}

//Readback of LCU safety table and memory patches, mode
mode HifiManCmd_readback_LCU_table_flight {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string section = "P" in ["P","R"];
}{
    mois_comment("Start LCU table and memory patch readback");
    StartMode_block_ops();
    mois_step("Read back memory patch content");
    LcuMemoryPatchReadback_ops(section);
    mois_step("Read back LCU safety table content");
    LcuSafetyTableReadback_ops();
    StopMode_block_ops();
    mois_spacon("Communicate the ObsID to the HIFI team, and check with them that the memory upload has been successful");
}

// Fourth part of WBS FM functional test, block
// Check effect of attenuators for laser 2
// NOT USED ANYMORE IN FM. STAYS AS A PLACEHOLDER FOR BLOCK NUMBER.
//block FT_WBS_att_laser2_fm HIFI 3702 {
//  string band="1a";	     // HIFI band
//  int integ_time = 4;      //Total integration time in sec.
//  }{
//}
//  WBS overall attenuator FM functional test, block
//  Done for laser1
block FT_WBS_att_overall_fm HIFI 3706 {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //
    //Set zero and comb off
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_OFF");
    delay(2);
    //
    //Initial configuration: overall attenuators set to max., individual attenuators to 0
    //H-Polarization
    //
    {double,string}[] result = ConfigurationReader("name_configwbs",["hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result[0]{0});
    string hwh_latchup_s = result[1]{1};
    int hwh_att_band4 = 0;
    int hwh_att_band3 = 0;
    int hwh_att_band2 = 0;
    int hwh_att_band1 = 0;
    int hwh_att_in = 16;
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result[0]{0});
    string hwv_latchup_s = result[1]{1};
    int hwv_att_band4 = 0;
    int hwv_att_band3 = 0;
    int hwv_att_band2 = 0;
    int hwv_att_band1 = 0;
    int hwv_att_in = 16;
    //
    //Loop on overall attenuators
    for(int i = 0 .. 15) {
        // Change the value of the main attenuator
        //========================================
        hwh_att_in = hwh_att_in - 1;
        hwv_att_in = hwv_att_in - 1;
        // Set WBS
        //========
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
    }
    //Set att. to max.
    WBS_config_proc_max_att_w_laser_fm(band,laser_H,laser_V);
    //
}

//HIFI-COP-X-HRS-Fast-Imix: Fast HRS chopped observations, combined with 21Hz oscillation investigation
obs HifiEng_stability_chopped_fasthrs_FastImix {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency in GHz
    string chopper_pair = "load" in ["load","sky"]; //internal load or sky on-off
    string with_lo_on = "true" in ["true","false"]; //Whether measurement with LO ON or not
}{
    //
    //General parameters in use
    int phaselength = 10;
    // Chop phase length
    int nchop = 12;
    // Number of phases
    double readout = 0.333;
    // HRS readout length
    double hrs_h_1 = 6.0;
    //Position in IF of HRS-H sub-band 1
    double hrs_h_2 = 6.0;
    //Position in IF of HRS-H sub-band 2 - not used
    double hrs_v_1 = 6.0;
    //Position in IF of HRS-V sub-band 1
    double hrs_v_2 = 6.0;
    //Position in IF of HRS-V sub-band 2 - not used
    //Needs to duplicate hrs_mode word:
    double[] hrs_subband = [hrs_h_1,hrs_h_2,hrs_v_1,hrs_v_2];
    // Check
    if(readout < 0.333) {
        error("We cannot readout both polarizations faster than at 3Hz");
    }
    //General parameters in use for Fast_Imix
    string polarization = "B";
    //mixer to be sampled: H, V or B. If B, they are done successively
    int milliSecSample = 3;
    // interval between samples
    int samplesBefore = 50;
    int samplesAfter = 1000;
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Stability_chopped_fasthrs_proc_ops(band,lo_freq,phaselength,nchop,readout,hrs_subband,chopper_pair,polarization,milliSecSample,samplesBefore,samplesAfter,with_lo_on));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Stability_chopped_fasthrs_proc_ops(band,lo_freq,phaselength,nchop,readout,hrs_subband,chopper_pair,polarization,milliSecSample,samplesBefore,samplesAfter,with_lo_on);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

////////////////////////////////////
// DBS cross observing mode - special version for Jupiter
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcJupiterDBSCross {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the two raster lines
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Engineering - Jupiter - DBS Cross Map slowChop",{data_time,0,0,n_switch_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    // Two changes relative to the normal DBS raster
    // 1) The longer load duration is enforced by zero resolution
    {double,double} loadResolution = {0.0,effResolution{1}};
    // 2) I assume that the tuning duration does not depend on the tuning level
    // so that the normal pre_timing can be reused.
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = DBSRaster_pre_timing(2,npoints,band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,double[],double[],int[],double,double,int,int,int,int,int,int} tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = custom_map_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSCross_post_timing(pre_timing,telescopetimes,npoints,n_switch_on,n_cycles,load_interval,false);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",post_timing{1},n_cycles);
    telescopetimes = custom_map_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int scansize = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        JupiterDBSRaster_commanding(band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,true);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = DBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,2,npoints,n_cycles,n_seq * imax(n_load,1),tact);
    // Correct for double counting of central point
    // The central point is returned only
    double multiplier = sqrt(0.5);
    noisevalues{0} = noisevalues{0} * multiplier;
    noisevalues{1} = noisevalues{1} * multiplier;
    noisevalues{2} = noisevalues{2} * multiplier;
    noisevalues{3} = noisevalues{3} * multiplier;
    noisevalues{4} = noisevalues{4} / multiplier;
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//Procedure checking and, if applicable, converting
//prime chopper sent voltage into redundant chopper sent voltage
double procedure Check_Chopper_Prime_Redundant_COP {
    double chopper_angle = 0.0; //prime chopper voltage
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Check prime or redundant status
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant","p_to_r_coeff_0","p_to_r_coeff_1","p_to_r_coeff_2","prime_endstop_min","prime_endstop_max","red_endstop_min","red_endstop_max"],"0",0.0);
    double chop = chopper_angle;
    double prime_endstop_min = result_d[4]{0};
    double prime_endstop_max = result_d[5]{0};
    double red_endstop_min = result_d[6]{0};
    double red_endstop_max = result_d[7]{0};
    //Change chopper voltage if necessary   
    if(prime_or_redundant == "Red") {
        chop = result_d[3]{0} * pow(chop,2.0) + result_d[2]{0} * chop + result_d[1]{0};
    }
    //Now check the chopper angle is within the ranges
    if(prime_or_redundant == "Prime") {
        if(chop > prime_endstop_max || chop < prime_endstop_min) {
            error("The chopper voltage (requested is " + chop + " V) in " + result_d[0]{1} + " mode has to be between " + prime_endstop_min + " and " + prime_endstop_max + " V.");
        }
    }
    if(prime_or_redundant == "Red") {
        if(chop > red_endstop_max || chop < red_endstop_min) {
            error("The chopper voltage (requested is " + chop + " V) in " + result_d[0]{1} + " mode has to be between " + red_endstop_min + " and " + red_endstop_max + " V.");
        }
    }

    return chop;
}

// LO SFT, following procedure of MPI, procedure
//  Uses routine approach with new TM TC call
procedure LO_SFT_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //
    double lo_freq = 0.0;
    double drain2_v = 0.0;
    double[] cresult_d = CalibrationReader("name_keyfreq",["keyfreq","key_d2v_P","key_d2v_R"],band,0.0);
    lo_freq = cresult_d[0];
    //applies to cold LO
    //Switch on with safe Vd2
    LCU_switchon_proc_fm(band);
    //LO freq and Vd2 to use is embedded in the proc
    //Wait total of 20 sec.
    delay(20);
    //Check what d2_v to use depending on test circumstances
    drain2_v = cresult_d[1];
    //Value for prime case, and fm H/W
    //
    if(prime_or_redundant == "Red") {
        drain2_v = cresult_d[2];
    }
    //
    LCU_config_nominal_w_D2_proc_fm(band,lo_freq,drain2_v);
}

{int,double,double,double,double,double} obs HifiSScanModeLoadChopNoRef {
    string modeName = "load-freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_cycles = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - Load Chop noRef",{data_time,0,0,0,0,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = SScanLoadChopNoRef_pre_timing(band,lo_freq,lo_freq_up,redundancy,effResolution,hr1,hr2,wb1,wb2,data_time,n_cycles,n_freq_point,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,double,double,int} tpar = Fine_telescope(naifid,onPosition,band,reffreq,pre_timing{0});
    // Dummy call to spacecraft command
    int[] telescopetimes = basic_fine_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,bool,int,int},double,double} post_timing = SScanChopNoRef_post_timing(pre_timing{0},telescopetimes);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = Fine_telescope(naifid,onPosition,band,reffreq,post_timing{1});
    // Call telescope command
    telescopetimes = basic_fine_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    // normal pre_timing values
    int loadlength = post_timing{1}{2};
    int n_per_on = post_timing{1}{4};
    int n_load_on = post_timing{1}{5};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        SScanLoadChopNoRef_commanding(band,reffreq,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,n_per_on,n_load_on,groupnumber,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SingleChop_deadtimes("lchop",band,reffreq,hr1,hr2,wb1,wb2,data_time,n_per_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanChopNoRef_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,n_per_on * imax(n_load_on,1),false,tscan,tdead);
    // Evaluate performance
    SScanChopNoRef_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_per_on * imax(n_load_on,1),groupnumber * n_freq_point,false,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

////////////////////////////////////
// Top-level procedures
////////////////////////////////////
//HIFI-COP-X-FastImix: 21Hz oscillation investigation
procedure Fast_Imix_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string polarization = "B" in ["H","V","B"]; //mixer to be sampled: H, V or B. If B, they are done successively
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50];
    int samplesAfter = 1000 in [0,1000];
}{
    //Need a representative frequency: take keyfreq
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result_d[0];
    //First measurement without LO
    //Force LO swith-off
    LCU_switch_off_block_fm();
    //FPU configuration
    Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
    //For HEBs, set bias to 3mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
        result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v"],band,lo_freq);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //Fast measurement
    Fast_Imix_block_fm(band,polarization,milliSecSample,samplesBefore,samplesAfter);
    //Second measurement with LO
    LCU_switchon_proc_fm(band);
    //Wait an extra delay of 1 min for short term stabilization
    delay(60);
    //For HEBs, set bias back to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
        result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //LO tuning
    LO_tuning_block_fm(band,lo_freq);
    //Fast measurement
    Fast_Imix_block_fm(band,polarization,milliSecSample,samplesBefore,samplesAfter);
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double} procedure DBSRaster_deadtimes {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval
    int n_chop = 3; // number of chop cycles in one integration
    int n_load = 0; // number of integrations in one pointing phase
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    double tdead = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Special meaning of n_load here
    if(n_load == 0) {
        int n_seq = 1;
    } else {
        n_seq = n_load;
    }
    // Compute parameters for the instrument timing
    {double,double} tinst = GetInstDeadSlowChop(data_time,2 * n_chop,"chop",band,lo_freq,backendreadoutparms);
    // dead time
    double tdeadint = double(data_time * 2 * n_chop) - tinst{0};
    // subtract dead times in switches
    // keep dead times between A-A and B-B in total dead time
    tdeadint = tdeadint - double(n_chop) * tinst{1};
    // Total dead time per cycle, only one point still not covered
    double tdead_tot = tdead + double(2 * n_seq) * tdeadint;
    // Integration time
    double tphaseint = tinst{0} / double(2 * n_chop);

    return {tdead_tot,tphaseint,tinst{1}};
}

//HIFI LO tuning for FSW and no cases, block
//Settings for both frequencies need to be common
//and are passed through lo_freq_setting
//Target current is read from look-up table
block LO_tuning_block_aot HIFI 6616 {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; //LO frequency at which to set LSU
    double lo_freq_setting = 978.3; //LO frequency at which to take the settings
    string mixer_polarization = "H" in ["H","V","B"]; //The polarization to be used for the tuning
    bool clearflags = true; // whether to reset LCU
    bool newsetting = true; // whether LSU/LOU parameters are new
    bool fswstorage = true; // whether FSW register shall be stored
}{
    //Store rest frequency
    double rest_lofreq = lo_freq;
    //LO frequency uncorrected from VelCorr
    double rest_lofreq_setting = lo_freq_setting;
    // Perform radial velocity correction
    lo_freq = VelCorrFreq(rest_lofreq);
    lo_freq_setting = VelCorrFreq(rest_lofreq_setting);
    //Get target mixer current
    {double,string}[] result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq_setting);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,rest_lofreq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double v_d2 = result[0]{0};
    drain2_v_start = min(v_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    //Recovey from potential failure mode
    if(clearflags) {
        Set_LO_Nominal_proc_aot();
    }
    //
    // Commanding of new parameters only if needed
    if(newsetting) {
        // Get all parameters needed to compute config_lo_delay in Configure_LCU
        //
        //Compute largest delay possible anticipating worst redshift
        // Maximum redshift given by maximum accepted radial velocity
        // Needs to be compliant with code in VelCorr
        // maxredshift=1 + 30.7km/s / 299999.6km/s;
        double maxredshift = 1.0001023;
        double drain2_bluemax_lowredshift = Get_BLUE_LIMIT_D2_proc_fm(band,rest_lofreq / maxredshift);
        result = ConfigurationReader(name_configlcutune,["drain2_v"],band,rest_lofreq / maxredshift);
        double drain2_lowredshift = min(result[0]{0} * (1.0 + tune_range / 2.0),drain2_bluemax_lowredshift);
        double drain2_bluemax_highredshift = Get_BLUE_LIMIT_D2_proc_fm(band,rest_lofreq * maxredshift);
        result = ConfigurationReader(name_configlcutune,["drain2_v"],band,rest_lofreq * maxredshift);
        double drain2_highredshift = min(result[0]{0} * (1.0 + tune_range / 2.0),drain2_bluemax_highredshift);
        //
        // Finally get config_lo_delay
        result = ConfigurationReader("name_delays",["lock_lo_delay","vd2_rampup_speed"],band,rest_lofreq);
        int config_lo_delay = iceil(result[0]{0} + (max(drain2_lowredshift,drain2_highredshift) - drain2_safe) / result[1]{0});
        //
        //Send command
        HIFI_Configure_LCU_proc_aot(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
        //
        //TM page dump and error flag clearance now contained in the above proc
    }
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    if(fswstorage) {
        HIFI_HL_store_tm_proc_fm();
    }
    //
    //Read TM pages and clear error flags after vector scan
    LCU_Read_TM_pages_proc_aot();
}

//HIFI-COP-7-EngInv: Investigation time - placeholder for planning
obs HifiEng_EngInv_COP {
    int test_duration = 3600; //duration in seconds
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(EngInv_COP_proc_ops(test_duration));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            EngInv_COP_proc_ops(test_duration);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// Wait a given time, procedure
//
procedure Wait_proc_fm {
    int wait_time = 100; //Time to wait, in seconds
}{
    delay(wait_time);
}

// Stability test, procedure, IF system
procedure Proc_stability_IF_system {
    string band = "1a"; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string mixer_polarization = "B" in ["H","V","B"]; //Polarization: H, V, or both (B) 
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    double mixer_bias = 8.0; //Mixer bias to be set during stability measurement
}{
    //Sets FPU with both IF on
    Init_all_IF_fm(band,mixer_polarization);
    //
    //Set mixer bias to 10mV for backend tuning prior to IF noise measurement
    {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_medium_resistive_h","bias_medium_resistive_v","bias_low_resistive_h","bias_low_resistive_v","bias_high_resistive_h","bias_high_resistive_h"],band,0.0);
    //
    double bias_medium_h = result[0]{0};
    double bias_medium_v = result[1]{0};
    double bias_low_h = result[2]{0};
    double bias_low_v = result[3]{0};
    double bias_high_h = result[4]{0};
    double bias_high_v = result[5]{0};
    //Set magnets to 0
    Set_Magnet_current_block_fm(0.0,0.0);
    //
    Mixerbias(bias_high_h,bias_high_v);
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_config_block_fm(band);
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        //Configure backends to max. attenuation
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration to default
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
    //Measure IF noise with high and low resistive bias
    Spectra_resistive_high_fm(band,bias_high_h,bias_high_v,4,"both");
    Spectra_resistive_low_fm(band,bias_low_h,bias_low_v,4,"both");
    //
    //Set to 8mV bias and do stability measurement
    //Mixerbias (bias_medium_h,bias_medium_v) ;
    //Now sets to user input bias
    Mixerbias(mixer_bias,mixer_bias);
    Stability_IF_system_fm(band,n,integ_time,backend,hrs_mode);
    //Configure spectrometers integration back to default
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
    //Set magnets back to nominal
    //Need a representative frequency: take keyfreq
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result_d[0];
    //
    result = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
    Set_Magnet_current_proc_fm(result[0]{0},result[1]{0});
    //
}

//Notify PDU status ON, procedure
//I assume all S/S are present
procedure HIFI_notify_PDU_status_on_proc_ops {
    string status_FCU = "ON" in ["ON","OFF"]; //Status of FCU
    string status_LCU = "ON" in ["ON","OFF"]; //Status of LCU
    string status_WBSV = "ON" in ["ON","OFF"]; //Status of WBSV
    string status_WBSH = "ON" in ["ON","OFF"]; //Status of WBSH
    string status_HRSV = "ON" in ["ON","OFF"]; //Status of HRSV
    string status_HRSH = "ON" in ["ON","OFF"]; //Status of HRSH
    string apply_to_subsystem = "FCU" in ["FCU","LCU","WBSH","WBSV","HRSH","HRSV","ALL"];
}{
    Hifi_HIFI_notify_PDU_status(status_FCU,status_LCU,status_WBSV,status_WBSH,status_HRSV,status_HRSH);
    delay(1);
    //Prepare message for operator: we will check whether one particular HK is ON
    if(status_FCU == "ON") {
        string subsyst_on = "HI_FCU_S";
    }
    if(status_WBSH == "ON") {
        subsyst_on = "HI_WBSH_S";
    }
    if(status_WBSV == "ON") {
        subsyst_on = "HI_WBSV_S";
    }
    if(status_HRSH == "ON") {
        subsyst_on = "HI_HRSH_S";
    }
    if(status_HRSV == "ON") {
        subsyst_on = "HI_HRSV_S";
    }
    if(status_LCU == "ON") {
        subsyst_on = "HI_LCU_S";
    }
    mois_tmcheck("Check that the HK parameter " + subsyst_on + " is ON.");
    //
    //Specific S/S check after switch on
    if(apply_to_subsystem == "FCU" || apply_to_subsystem == "ALL") {
        //check OBS version
        {double,string}[] result = ConfigurationReader("name_delays",["hi_sw_version","hi_sw_revision","hi_sw_patch"],"0",0.0);
        int hi_sw_version = iround(result[0]{0});
        int hi_sw_revision = iround(result[1]{0});
        int hi_sw_patch = iround(result[2]{0});
        mois_tmcheck("Check that HI_SW_Version is " + hi_sw_version);
        mois_tmcheck("Check that HI_SW_Revision is " + hi_sw_revision);
        mois_tmcheck("Check that HI_SW_Patch is " + hi_sw_patch);
    }
    if(apply_to_subsystem == "WBSH" || apply_to_subsystem == "ALL") {
        //This is now done at end of procedure as instrument mode status check
        //mois_tmcheck("Check that both parameters HWH_Laser1_S and HWH_Laser2_S are OFF");
        //mois_tmcheck("Check that parameter HWH_Zero_S is ON");
        //mois_tmcheck("Check that parameter HWH_IN_ATT is set to 15, and parameters HWH_Band_1_ATT, HWH_Band_2_ATT, HWH_Band_3_ATT, HWH_Band_4_ATT are set to 7");
    }
    if(apply_to_subsystem == "WBSV" || apply_to_subsystem == "ALL") {
        //This is now done at end of procedure as instrument mode status check
        //mois_tmcheck("Check that both parameters HWV_Laser1_S and HWV_Laser2_S are OFF");
        //mois_tmcheck("Check that parameter HWV_Zero_S is ON");
        //mois_tmcheck("Check that parameter HWV_IN_ATT is set to 15, and parameters HWV_Band_1_ATT, HWV_Band_2_ATT, HWV_Band_3_ATT, HWV_Band_4_ATT are set to 7");
    }
    if(apply_to_subsystem == "HRSH" || apply_to_subsystem == "ALL") {
        //This is now done at end of procedure as instrument mode status check
        //mois_tmcheck("Check that parameters HRH_1U_ATT, HRH_1L_ATT, HRH_2U_ATT, HRH_2L_ATT, HRH_3U_ATT, HRH_3L_ATT, HRH_4U_ATT and HRH_4L_ATT are set to 15.5"); 
    }
    if(apply_to_subsystem == "HRSV" || apply_to_subsystem == "ALL") {
        //This is now done at end of procedure as instrument mode status check
        //mois_tmcheck("Check that parameters HRV_1U_ATT, HRV_1L_ATT, HRV_2U_ATT, HRV_2L_ATT, HRV_3U_ATT, HRV_3L_ATT, HRV_4U_ATT and HRV_4L_ATT are set to 15.5");   
    }
    if(apply_to_subsystem == "LCU" || apply_to_subsystem == "ALL") {
        //This is now done at end of procedure as instrument mode status check
        //mois_tmcheck("Check that parameter HL_MODE_S is standby");
        //mois_tmcheck("Check that parameter HL_Channel_S is OFF");
    }
}

// HRS linearity check, loop on individual attenuators, mode
// The WBS attenuators are also changed at the same time
// =======================================================
block HRS_linearity_indiv_block_fm HIFI 3660 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec.
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //Fetch resistive bias
    {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_high_resistive_h","bias_high_resistive_v","bias_medium_resistive_h","bias_medium_resistive_v"],band,0.0);
    //
    double bias_high_h = result[0]{0};
    double bias_high_v = result[1]{0};
    double bias_medium_h = result[2]{0};
    double bias_medium_v = result[3]{0};
    int repeats = 32;
    double hrsH_attenuators_value = 15.5;
    double hrsV_attenuators_value = 15.5;
    //Test will be done in WB mode for both polar
    string hrsh_blocks_configuration = "corr_wide";
    string hrsv_blocks_configuration = "corr_wide";
    // Configure spectroscopy
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    // Configure blocks
    //=================
    //H-polar
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration);
    // 
    //delay(1);
    //V-polar
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration);
    // 
    delay(1);
    // Fetch internal LO settings
    //===========================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    double[] hrsH_LO = [result[1]{0},result[2]{0},result[3]{0},result[4]{0},result[5]{0},result[6]{0},result[7]{0}];
    string hrs_polarization_h = result[0]{1};
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    double[] hrsV_LO = [result[1]{0},result[2]{0},result[3]{0},result[4]{0},result[5]{0},result[6]{0},result[7]{0}];
    string hrs_polarization_v = result[0]{1};
    //
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    //
    ///////////////////////////////////////
    //Now prepare WBS
    //Set zero and comb off
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_OFF");
    delay(2);
    //
    //Initial configuration: overall attenuators set to max., individual attenuators to 0
    //H-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result[0]{0});
    string hwh_latchup_s = result[1]{1};
    int hwh_att_band4 = 0;
    int hwh_att_band3 = 0;
    int hwh_att_band2 = 0;
    int hwh_att_band1 = 0;
    int hwh_att_in = 15;
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwh_heater","hwh_latchup_s"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result[0]{0});
    string hwv_latchup_s = result[1]{1};
    int hwv_att_band4 = 0;
    int hwv_att_band3 = 0;
    int hwv_att_band2 = 0;
    int hwv_att_band1 = 0;
    int hwv_att_in = 15;
    //
    // Loops on the different configurations of the HRS attenuators
    //===============================================
    //Magnets shall be set to 0 since high biases will be used
    Set_Magnet_current_proc_fm(0.0,0.0);
    //
    for(int i = 0 .. repeats - 1) {
        // Configure attenuators and LO
        //=============================
        Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
        // 
        //delay(2);
        Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsH_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
        // 
        delay(1);
        ///////////////////////
        //Configure WBS
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        //delay(wbs_config_delay);
        //
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //
        //Set the shot noise to high resistive bias
        Mixerbias(bias_high_h,bias_high_v);
        // Take spectrum
        //==============
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
        //
        //Set the shot noise to medium resistive bias
        Mixerbias(bias_medium_h,bias_medium_v);
        // Take spectrum
        //==============
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
        // Change the value of the 8 attenuators
        //======================================
        hrsH_attenuators_value = hrsH_attenuators_value - 0.5;
        hrsV_attenuators_value = hrsV_attenuators_value - 0.5;
        // Change the value of the main WBS attenuator:
        //============================================
        if(hwh_att_in > 0) {
            hwh_att_in = hwh_att_in - 1;
            hwv_att_in = hwv_att_in - 1;
        } else {
            hwh_att_in = 0;
            hwv_att_in = 0;
        }
    }
    //Set magnets back to normal settings
    //Need a representative frequency: take keyfreq
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result_d[0];
    //
    result = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
    Set_Magnet_current_proc_fm(result[0]{0},result[1]{0});
    //
}

//Peak up simulation in ILT, procedure
//Shutter is used to partially blind external BB load
procedure Peakup_test_proc_fm {
    int band = 1 in [1,7]; // HIFI band
    string backend = "hrs" in ["hrs","wbs"]; //Backend in use: hrs or wbs
    int integ_time = 2; //Total integration time in sec.
    string mixer_polarization = "H" in ["H","V"]; //mixer polarization to be used 
    string peakup_matrix = "centred" in ["centred","offseted","flat"]; //Which brightness distribution to simulate with shutter: centred, offseted, flat
}{
    string band_nb = "" + band + "a";
    //Configure backend in total power
    int[] res = Configure_Spectrometer_peakup_proc_fm(band_nb,integ_time,["wb1","wb1"],backend,mixer_polarization);
    int total_time = res[0] * res[1];
    if(backend == "wbs") {
        WBS_config_block_fm(band_nb);
        WBS_tune_proc_fm(band_nb);
    }
    //If HRS need to provide IF input power
    if(backend == "hrs") {
        double[] deflofreq = [522.0,652.0,807.0,979.0,1152.0,1520.0,1746.0];
        Init_MSA_fm(band_nb,"CLOSE",deflofreq[band - 1],"ON");
        //Set mixer bias to 5mV
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_low_resistive_h","bias_low_resistive_v"],band_nb,0.0);
        //
        double bias_low_h = result[0]{0};
        double bias_low_v = result[1]{0};
        //Set magnets to 0
        Set_Magnet_current_block_fm(0.0,0.0);
        //
        Mixerbias(bias_low_h,bias_low_v);
    }
    //configure peak-up aquisition mode
    Peakup_test_configure_block_fm("" + band + "",mixer_polarization);
    //trigger measurement at all 9 positions
    Peakup_test_acquire_data_block_fm("" + band + "",backend,total_time,peakup_matrix,mixer_polarization);
    //
}

//Set LCU3b back to standby status, procedure
procedure LCU3b_standby_proc_fm {
    string band = "3b"; // HIFI band
    double lo_freq = 900.0 in [852.0,953.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

// Procedure for zero and comb measurement 
// Collects all common parts for LoadMeasurement and DoubleLoadMeasurement
//
procedure ZeroCombMeasurement {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double lo_freq = 978200.0; // LO frequency
    int used_datatime = 4; // time between subsequent data readouts in load
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
}{
    // Usage of WBS
    bool wbs1used = backendreadoutparms{2}{0};
    bool wbs2used = backendreadoutparms{3}{0};
    // Zero and Comb measurement is only used in WBS observations
    if(wbs1used || wbs2used) {
        // Now start the zero-comb measurement
        int danglingreadout = WBS_Zero_Comb(band,lo_freq);
        // Add possible delay needed before next zero measurement
        if(used_datatime < danglingreadout) {
            delay(danglingreadout - used_datatime);
        }
        // Perform the first zero measurement with the settings of the
        // regular observations
        // 
        //   I use the optimistic approach to completely omit this step now
        //   danglingreadout=WBS_Full_Zero(band,lo_freq,used_datatime,
        //    					backendreadoutparms);
        //   // Add possible delay needed before hot-cold measurement
        //   if (used_datatime < danglingreadout) {
        //     delay(danglingreadout-used_datatime);
        //   }
    }
}

{string,double,double}[] procedure HifiMappingModeFastDBSRasterSequencerInit {
    string modeName = "raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get the drift parameters to compute the drift noise
    {double,double} phaselengths = DBSPhaseLengths(band,lo_freq,effResolution,continuumDetection,oneGHzReference);
    // Compute derived quantities
    // Top down approach here
    int main_phase = iceil(phaselengths{0});
    // Arbitrary selection of data_time
    int data_time_guess = 20;
    // Combine points for n_switch=1
    int n_pointsperscan_guess = imin(imax(main_phase / data_time_guess,1),npoints * nlines);
    int n_pointsperscan_range = 1 - n_pointsperscan_guess;
    if(n_pointsperscan_range == 0) {
        n_pointsperscan_range = 1;
    }
    // remaining part for n_switch
    int n_switch_on_guess = main_phase / (n_pointsperscan_guess * data_time_guess) + 1;
    data_time_guess = main_phase / (n_pointsperscan_guess * n_switch_on_guess);
    // Check with data rate
    {int,double[]} dataparms = DataTaking(backendreadoutparms,8);
    int datalimit = 2 * dataparms{0};
    if(data_time_guess < datalimit) {
        data_time_guess = datalimit;
        n_switch_on_guess = 1;
    }
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // Chop phase length
    double phase_min = min(max(phaselengths{1},0.15),1.5);
    int n_int_on_guess = ifloor(double(data_time_guess) / (2.0 * phase_min));
    int n_int_on_range = -n_int_on_guess / 2;
    if(n_int_on_range == 0) {
        n_int_on_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_int_on",double(n_int_on_guess),double(n_int_on_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_pointsperscan",double(n_pointsperscan_guess),double(n_pointsperscan_range)}];

    return retvalues;
}

// Load OBSW in intermediate mode, mode
mode HifiManCmd_load_OBSW {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    Mode_status_check_intermediate();
    StartMode_block_ops();
    mois_comment("Start loading of a new OBSW in intermediate mode");
    Load_OBSW_block_ops();
    StopMode_block_ops();
}

///////////////////////////////////////////////////////
// Generic procedures to configure various S/S in HIFI
//Configure FPU at frequency of interest:
//	- set nominal bias, magnet currents and diplexer currents
//	- set IF amp. to nominal
//	- look at internal HBB
//	- set chopper parameter, use of CLOSED loop 
//	- checks whether one of the polarization is not used
//	- DT 250707: added code to allow LO band switch on
//
//Configure FPU
procedure ConfigureFPU {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    bool power_fcu = true; //whether needs full FPU configuration (true) or just freq-dependent adjustement (false)
}{
    //We always setup both polarizations although one of them may not be used
    //This has only effect on data readouts, not on hardware settings
    Init_MSA_aot(band,"CLOSE",lo_freq / 1000.0,power_fcu,"ON");
}

// Check of Bragg cell heating using internal attenuators, block
block FT_WBS_BraggCell_att_fm HIFI 3711 {
    string band = "1a"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON 
    int[] att_h = [7,7,7,7,12]; //User input att. for optimum level H-polar: DO A TUNING FIRST !
    int[] att_v = [7,7,7,7,12]; //User input att. for optimum level V-polar: DO A TUNING FIRST !
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //
    //Test continuum signal response
    //1. Set WBS attenuators to work at nominal level 
    //for the current input (minimum attenuation without saturation)
    //It practice the CUS cannot read back the optimum settings from 
    //a tuning...instead we consider they are input
    //We assume the test is done after a tuning.
    //Must be done manually...
    //
    {double,string}[] result = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4","hwh_att_band3","hwh_att_band2","hwh_att_band1","hwh_att_in"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result[2]{0});
    string hwh_latchup_s = result[3]{1};
    int hwh_att_band4 = att_h[3];
    //iround(result[4]{0});
    int hwh_att_band3 = att_h[2];
    //iround(result[5]{0});
    int hwh_att_band2 = att_h[1];
    //iround(result[6]{0});
    int hwh_att_band1 = att_h[0];
    //iround(result[7]{0});
    int hwh_att_in = att_h[4];
    //iround(result[8]{0});
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //
    result = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4","hwv_att_band3","hwv_att_band2","hwv_att_band1","hwv_att_in"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result[2]{0});
    string hwv_latchup_s = result[3]{1};
    int hwv_att_band4 = att_v[3];
    //iround(result[4]{0});
    int hwv_att_band3 = att_v[2];
    //iround(result[5]{0});
    int hwv_att_band2 = att_v[1];
    //iround(result[6]{0});
    int hwv_att_band1 = att_v[0];
    //iround(result[7]{0});
    int hwv_att_in = att_v[4];
    //iround(result[8]{0});
    //
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //2. Configure spectroscopy and do integration: total of 100s with 4s integration
    Total_power_spectro_for_Stability_proc_fm(band,25,4,backend,["wb1","wb1"]);
    //
    //Increase main attenuator by 3 dB
    hwh_att_in = hwh_att_in + 3;
    hwv_att_in = hwv_att_in + 3;
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Integrate with the WBS
    Total_power_spectro_for_Stability_proc_fm(band,25,4,backend,["wb1","wb1"]);
    //
    //Decrease main attenuator again by 3 dB
    hwh_att_in = hwh_att_in - 3;
    hwv_att_in = hwv_att_in - 3;
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Integrate with the WBS
    Total_power_spectro_for_Stability_proc_fm(band,25,4,backend,["wb1","wb1"]);
    //
    //Increase main attenuator again by 3 dB
    hwh_att_in = hwh_att_in + 3;
    hwv_att_in = hwv_att_in + 3;
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Integrate with the WBS
    Total_power_spectro_for_Stability_proc_fm(band,25,4,backend,["wb1","wb1"]);
    //
    //Settling time of COMB
    //We have to set attenuators to values different from max.
    //12,3,3,3,3: info from Oliver Sibertz. This may change for FM
    //Initial configuration
    //H-Polarization
    result = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4_comb","hwh_att_band3_comb","hwh_att_band2_comb","hwh_att_band1_comb","hwh_att_in_comb"],band,0.0);
    hwh_laser1_s = "OFF";
    hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    hwh_heater = iround(result[2]{0});
    hwh_latchup_s = result[3]{1};
    hwh_att_band4 = iround(result[4]{0});
    hwh_att_band3 = iround(result[5]{0});
    hwh_att_band2 = iround(result[6]{0});
    hwh_att_band1 = iround(result[7]{0});
    hwh_att_in = iround(result[8]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4_comb","hwv_att_band3_comb","hwv_att_band2_comb","hwv_att_band1_comb","hwv_att_in_comb"],band,0.0);
    hwv_laser1_s = "OFF";
    hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    hwv_heater = iround(result[2]{0});
    hwv_latchup_s = result[3]{1};
    hwv_att_band4 = iround(result[4]{0});
    hwv_att_band3 = iround(result[5]{0});
    hwv_att_band2 = iround(result[6]{0});
    hwv_att_band1 = iround(result[7]{0});
    hwv_att_in = iround(result[8]{0});
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Set Zero and COMB ON
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_ON");
    delay(2);
    //
    //Integrate with the WBS
    Total_power_spectro_for_Stability_proc_fm(band,25,4,backend,["wb1","wb1"]);
    //
    //Still TBD here: [Perform comb measurements for different Bragg cell heat levels]
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_OFF");
    delay(1);
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_OFF");
    delay(1);
    //Configure Spectroscopy
    //Configure_Spectrometer_proc_fm(band,4,["wb1","wb1"]);
}

// Step 2 of QLA_Testcontrol fine magnet-tuning loop
block Magnet_set_fine_with_IVcurve_fm HIFI 3204 {
    string band = "1a";
}{
    Start_block();
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["bias_min_h","bias_max_h","bias_steps_h","bias_min_v","bias_max_v","bias_steps_v"],band,0.0);
    //H polar
    double bias_min_h = result_d[0]{0};
    double bias_max_h = result_d[1]{0};
    int steps_h = iround(result_d[2]{0});
    //V polar
    double bias_min_v = result_d[3]{0};
    double bias_max_v = result_d[4]{0};
    int steps_v = iround(result_d[5]{0});
    //Bias to set at end of IVC
    //Need a representative frequency: take keyfreq
    double[] result = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result[0];
    //
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v","norm_magn_h","norm_magn_v"],band,lo_freq);
    double bias_h = result_d[0]{0};
    double bias_v = result_d[1]{0};
    //Fetch magnets only if band is not band6
    double magnetcurrent_h = 0.0;
    double magnetcurrent_v = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        magnetcurrent_h = result_d[2]{0};
        magnetcurrent_v = result_d[3]{0};
    }
    //
    //The IVCurve is done on the smallest range and the finest step
    double bias_min = max(bias_min_h,bias_min_v);
    double bias_max = min(bias_max_h,bias_max_v);
    int steps = iround(max(double(steps_h),double(steps_v)));
    //
    //First set magnets to max.
    double magnet_current_max_h = 0.0;
    double magnet_current_max_v = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
        magnet_current_max_h = result_d[0]{0};
        magnet_current_max_v = result_d[1]{0};
    }
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_current_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_current_max_v);
    delay(1);
    //Do IV curve
    IVcurve(band,bias_min,bias_max,steps,magnetcurrent_h,magnetcurrent_v,bias_h,bias_v);
}

//  LCU configuration with no retune, block
//  Uses best guess D2 voltage from latest LO tuning
block LCU_config_nominal_noretune_block_aot HIFI 6614 {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; //LO frequency
    bool fswstorage = true; // whether FSW register shall be stored
}{
    //Store rest frequency
    double rest_lofreq = lo_freq;
    //LO frequency uncorrected from VelCorr
    // Perform radial velocity correction
    lo_freq = VelCorrFreq(rest_lofreq);
    //Fetch LO parameters
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,rest_lofreq);
    int config_lo_delay = iround(result[0]{0});
    //Send command
    Hifi_HIFI_Conf_f_LCU_noretune($BBID,freq_nx,lsu_main,lsu_offset);
    //
    delay(config_lo_delay);
    //Store settings into available register
    if(fswstorage) {
        HIFI_HL_store_tm_proc_fm();
    }
}

////////////////////////////////////////
// Standing wave analysis combined with stability measurement, procedure
// It uses only the WBS in a specific setup. 
// Otherwise, re-use of Stability_intcold_fm code
procedure Standing_wave_w_stability_fm {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    double[] lo_freq_input = [500.0,500.15,0.02]; //Start, end and step lo_freq for the LO scan
    int n = 100; //The number of integrations
}{
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_stndwave_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration after tuning
    int[] res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    //Loop on LO frequencies. It is assumed that the LO is tuned at the initial frequency
    double lo_freq = lo_freq_input[0];
    while(lo_freq <= lo_freq_input[1]) {
        //Set synthesizer to new LO freq.
        LCU_config_nominal_proc_fm(band,lo_freq);
        //
        //Noise temperature measurement to check sensitivity change with LO frequency
        Hot_cold(band,hrs_mode,backend,res[0] * res[1],"tp",0,0);
        //integration on internal loads
        //
        //Stability measurement on cold internal source
        //Radiometry_stability_fm(band,n,hrs_mode,"wbsFast");	//Complementary ~100-200 sec. stability measurement
        //
        //Configure spectrometers integration back to default
        res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
        //Increase lo_freq
        lo_freq = lo_freq + lo_freq_input[2];
    }
    //
}

/////////////////////////////////////////////////////////////////
// Slow chop dual beam switch observing mode
// 
// Combination of four modules implementing the new structure 
//
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiPointProcDBS {
    /* Setup parameters */
    int naifid = 0; // Tracing object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Single Point - DBS slowChop",{data_time,0,0,n_switch_on,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,bool,int,int,int} pre_timing = DBS_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},bool,double,double} post_timing = DBS_post_timing(pre_timing,telescopetimes,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",post_timing{1},n_cycles);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_seq = post_timing{1}{8};
    int n_loadinterval = post_timing{1}{7};
    bool end_load = post_timing{1}{9};
    int shiftlength = post_timing{1}{10};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        DBS_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,n_loadinterval,end_load,final_load,startobs,telescopetimes,loadlength,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = DBS_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBS_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,n_seq * (n_load + 1),tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// General HIFI performance test to be run at key frequencies
// Assumes that a SFT has been previously performed
procedure HIFI_Performance_proc_fm {
    string band = "1a"; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //
    //FPU configuration
    Init_MSA_fm(band,"CLOSE",lo_freq,"ON");
    //backend config
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_config_block_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_config_block_fm(band,hrs_mode);
    }
    //Set-up LO at new frequency and performs tuning at that frequency. 
    //Assumes the band was already switched on prior to the performance test
    //Also assumes we are in nominal mode.
    LO_tuning_block_fm(band,lo_freq);
    //The mixer to use is checked in a table  
    //
    //Now start measurements corresponding to FT pumped
    IVcurve_pumped_fm(band,lo_freq);
    //
    //Magnet tuning: only up to band 5 since band6-7 have no magnets
    string backend_code = "HRS";
    //our experience is that HRS is doing fine for mag tuning
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        {double,string}[] result_d = ConfigurationReader("name_configwbs",["tune_target_magnet"],band,lo_freq);
        int tune_target_magnet = iround(result_d[0]{0});
        Magnet_tuning_block_fm(band,lo_freq,backend_code,tune_target_magnet);
    }
    //
    //Spectrometer attenuator tuning: should be done on Hot source
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers after tuning
    int[] res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //HotCold measurement
    Hot_cold(band,hrs_mode,backend,res[0] * res[1],"tp",0,0);
    //
    //Finally, perform chopper scan from M3_right to end stop
    //it is done in slowchop mode to avoid short term instabilities
    //
    //DT - from FM_CUS_9.15.2 onwards, chopper scan is done out of this testmode
    //
    res = Configure_Spectrometer_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    int total_time = res[0] * res[1];
    int n_steps = 100;
    int n_wbs1 = 0;
    //we use the slowchop mode
    int n_hrs_trans = 0;
    //we use the slowchop mode
    double chop_phase = 1.0;
    //we use the slowchop mode
    //Get voltages for start and end positions
    result_d = ConfigurationReader("name_confilfpu",["chop_M3right","chop_endstopright"],band,0.0);
    double chopper_pos_min = result_d[0]{0};
    double chopper_pos_max = result_d[1]{0};
    //Chopper_scan_fm (band, chopper_pos_min, chopper_pos_max, n_steps,total_time,backend,"slowchop",n_wbs1,n_hrs_trans,false,shutter_used,hrs_mode,chop_phase) ;
    //
}

//HIFI LO tuning, block for experts: allow all vector scan parameters as user input
//Target current is read from look-up table
block LO_tuning_EXPERT_block_fm HIFI 3613 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string mixer_polarization = "H" in ["H","V","B"]; //The polarization to be used for the tuning
    double target_current = 1.0; //Target mixer current
    double step_drain2_v = 2.0; //D2_V steps during vector scan
    int nsteps = 10; //Number of steps. Should not be larger than 10
    double step_time = 1.0; //In seconds.
    double drain2_v_start = 1.5; //Starting D2_V in vector scan
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    //double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //For bands 1 to 5, scan will be done with increasing drain2 voltages
    //
    //For bands 6 to 7, scan will be done with decreasing drain2 voltages
    if(band == "6a" || band == "7a" || band == "6b" || band == "7b") {
        step_drain2_v = -1.0 * step_drain2_v;
    }
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    //delay(1);
    //
    //Execute tuning: check which mixer is to be used
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

// Detector heater control: AOT version does not switch magnet back to normal at end
block Heater_block_aot HIFI 6940 {
    string band = "4a";
}{
    //Get name of FPU configuration file
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["normal_heater_time_h","normal_heater_time_v","heater_delay_h","heater_delay_v","magnet_current_max_h","magnet_current_max_v"],band,0.0);
    double normal_heater_time_h = result_d[0]{0};
    double normal_heater_time_v = result_d[1]{0};
    int heater_delay_h = iround(result_d[2]{0});
    int heater_delay_v = iround(result_d[3]{0});
    //Magnets need to be switched to 0 prior to the deflux
    Hifi_HIFI_CH1_MX_MG_C($BBID,0.0);
    Hifi_HIFI_CV1_MX_MG_C($BBID,0.0);
    delay(1);
    //
    Hifi_HIFI_HF_CH1_DHTR_C($BBID,normal_heater_time_h);
    delay(iceil(normal_heater_time_h / 1000.0) + 1);
    //
    int startobs = time();
    //Extra delay for cooling down temperature: will be included in the V-mixer delay
    //delay(heater_delay_h);
    Hifi_HIFI_HF_CV1_DHTR_C($BBID,normal_heater_time_v);
    delay(iceil(normal_heater_time_v / 1000.0) + 1);
    //Extra delay for cooling down temperature: both mixers cool down together
    delay(heater_delay_v);
    //
}

//HIFI LO tuning, procedure
procedure LO_tuning_block_fm_1a {
    double target_current = 1.0; //Target mixer current
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 570.0; //LO frequency
    string mixer_polarization = "H" in ["H","V"]; //The polarization to be used for the tuning
}{
    error("This module is obsolete: use LO_tuning_block_fm instead");
}

//////////////////////////////////////////////////////////////////////////
// Procedure to generate the parameters for the telescope command 
// and to check all input parameters
{int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} procedure DBS_telescope {
    int naifid = 0; // Tracing object ID
    {double,double} onposition = {0.0,0.0}; // Coordinates of the source
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    string throw = ""; // Identifier for chop throw, empty is standard
    {int,int,int,int,int,int,int,int,int,bool,int,int,int} timing = {4,10,4,21,11,1800,0,10,1,false,0,50,0}; // full timing parameter list
    int n_cycles = 2; // Number of half OFF-ON-ON-OFF cycles
}{
    // Assign values
    int pointing = timing{1};
    // Pointing during in one phase
    int loadlength = timing{3};
    // Load duration
    int n_loadinterval = timing{7};
    //No. of nods between load measurements
    int initlength = timing{11};
    // Initial setup time
    int dangling = timing{12};
    // Final load measurement
    // Create variables for telescope command
    string ib = GetBoresight(band,lo_freq,true);
    // A change of ra-dec depending on naifid may be needed
    double ra = onposition{0};
    double dec = onposition{1};
    // pattern angle and throw of the chopper direction
    double[] chopper = GetSkyChopThrow(band,lo_freq,throw);
    double nodlength = chopper[0];
    double patt = chopper[1];
    nodlength = max(nodlength * 3600.0,2.0);
    // Check parameter compatibility with pointing command for parameters
    // which are no direct input parameters
    if(n_cycles > 1200) {
        IError("Too many noddings. Break up the observation into smaller pieces.");
    }
    if(pointing < 10) {
        SError("Pointing phase length too short. Increase the number of integrations.");
    }
    if(pointing > 50000) {
        SError("Pointing phase length too long. Reduce the number of integrations.");
    }
    if(nodlength > 7200.0) {
        IError("Nodding length too long. Choose a smaller chop throw.");
    }
    // repetition at multiple frequencies not yet implemented:
    int thold = 0;
    int nhold = 0;
    int n_repeat = n_cycles;
    // return parameters in required order

    return {initlength,0,dangling,ib,naifid,ra,dec,false,patt,0.0,0.0,n_repeat,nodlength,pointing,pointing,loadlength,n_loadinterval,thold,nhold};
}

///////////////////////////////////////////////
// Functions useful for almost all observing modes
// Perform consistency check for long observations 
// where readout time <= data time 
procedure CheckDataTaking {
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
    int data_time = 4; // Integration time between two data readouts
}{
    // Compute chunk size given by the data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    if(dataparms{0} > data_time) {
        SError("Maximum data rate does not allow to dump backends every " + data_time + "s.");
    }
}

// WBS configuration, block
// Both polarizations are treated
block WBS_config_block_aot HIFI 6625 {
    string band = "4a"; // HIFI band
}{
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4","hwh_att_band3","hwh_att_band2","hwh_att_band1","hwh_att_in"],band,0.0);
    string hwh_laser1_s = result_d[0]{1};
    string hwh_laser2_s = result_d[1]{1};
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = iround(result_d[4]{0});
    int hwh_att_band3 = iround(result_d[5]{0});
    int hwh_att_band2 = iround(result_d[6]{0});
    int hwh_att_band1 = iround(result_d[7]{0});
    int hwh_att_in = iround(result_d[8]{0});
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4","hwv_att_band3","hwv_att_band2","hwv_att_band1","hwv_att_in"],band,0.0);
    string hwv_laser1_s = result_d[0]{1};
    string hwv_laser2_s = result_d[1]{1};
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = iround(result_d[4]{0});
    int hwv_att_band3 = iround(result_d[5]{0});
    int hwv_att_band2 = iround(result_d[6]{0});
    int hwv_att_band1 = iround(result_d[7]{0});
    int hwv_att_in = iround(result_d[8]{0});
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
}

/////////////////////////////////////////////////////////////////
// Procedure to call ConfigSpectroscopy for fast chop with a single command
//
int[] procedure ConfigFastChop {
    int observing_time = 12; // Integration time
    double chop_phase = 0.5 in [0.125,2.0]; // Chop phase length
    string band_number = "1a"; // HIFI band
    double lo_freq = 522000.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1 {used,resolution,subbands used}, HRS2 , WBS1 {used, channel windows}, WBS2 
}{
    // Use only 24 bit mode here
    int dpmax = observing_time / 2;
    {int,double[]} dataparms = DataTaking(backendreadoutparms,dpmax);
    int dpmin = 2 * dataparms{0};
    if(observing_time < dpmin) {
        error("The total integration time of " + observing_time + "s is too short " + "for a fast chop measurement.");
    }
    // split integration time
    int data_time = 0;
    int n_data = 0;
    // Construct possible read out times
    dpmax = 160;
    // WBS ICD
    for(int idiv = dpmin .. dpmax) {
        if(observing_time % idiv == 0) {
            data_time = idiv;
            n_data = observing_time / idiv;
        }
    }
    if(data_time == 0) {
        error("The integration time of " + observing_time + "s cannot be split " + "into equal integrations  <= 10s.");
    }
    // Split into chop cycles
    int wbs_overhead = 2;
    int n_chop = ifloor(double(data_time - wbs_overhead) / (2.0 * chop_phase));

    return [data_time,n_data,n_chop];
}

// Return standard readout setting used in frequency calibration
{{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} procedure FrequencyCalibrationParms {
    bool usewbs1 = true; // whether the WBS1 is used
    bool usewbs2 = true; // whether the WBS2 is used
    bool usehrs1 = false; // whether the HRS1 is used
    bool usehrs2 = false; // whether the HRS2 is used
}{
    {bool,int,bool[]} hrs1 = {usehrs1,3,[true,true,true,true]};
    {bool,int,bool[]} hrs2 = {usehrs2,3,[true,true,true,true]};
    {bool,int[][]} wbs1 = {usewbs1,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {usewbs2,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {hrs1,hrs2,wbs1,wbs2};

    return backendreadoutparms;
}

//Reduced version: IVC only
//HIFI-COP-7.2-LO_FT
obs HifiEng_LO_FT_IVC_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(LO_FT_IVC_COP_proc_ops(band,prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            LO_FT_IVC_COP_proc_ops(band,prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

//HIFI-COP-2.1-DPL-RespTime
procedure Diplexer_Response_time_COP_proc_ops {
    string band = "3a" in ["3a","4a","6a","7a"];
    string mixer_polarization = "H"; //mixer polarization: H or V
}{
    //Get keyfreq
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result_d[0];
    //Series of diplexer settings to move to
    double[] dipl_curr = [1.5,-1.5,1.5,0.1,-0.1,0.1,1.3,1.5,1.3,-1.3,-1.5,-1.3];
    //Define engineering scan parameters
    int milliSecSample = 3;
    // interval between samples
    int samplesBefore = 30;
    // HIF_N_samples_1
    int samplesAfter = 1000;
    // HIF_N_samples_2
    double bandnb = GetBandCode(band);
    string tabfilter = "config_dipfilter.config";
    //Loop on filter parameters
    for(int j = 1 .. 4) {
        //Retrieve filters from LUT
        int dipfilter = ilookup(tabfilter,"" + iceil(bandnb),"filter_" + j);
        //Initialise MSA with this filter
        Init_MSA_DipFilter_fm(band,"CLOSE",lo_freq,"ON",dipfilter);
        //Loop on pairs
        for(int i = 0 .. 3) {
            //Set diplexer to starting point
            Set_Diplexer_current_block_fm(dipl_curr[i * 3],dipl_curr[i * 3]);
            //Start series of diplexer motion and measure response time 
            Diplexer_engineering_scan_block_fm(mixer_polarization,dipl_curr[i * 3 + 1],milliSecSample,samplesBefore,samplesAfter);
            Diplexer_engineering_scan_block_fm(mixer_polarization,dipl_curr[i * 3 + 2],milliSecSample,samplesBefore,samplesAfter);
            //Engineering_scan_for_diplexer_resp_block_ops(milliSecSample,samplesBefore,samplesAfter);
        }
    }
}

/////////////////////////////////////////////////////////////////
// Procedure to derive often used backend settings
// Derived from spectral-scan-mode and genericCode
//
{{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} procedure BackendSettings {
    string band = "1a"; // HIFI band
    double lo_freq = 522000.0; // LO frequency
    string[] hrs_mode = ["wb2","wb2"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Fetch parameters applicable to the backend case
    string spec_filename = "name_confilspec";
    //For tp and chop
    if(backend == "wbsFast") {
        spec_filename = "name_confilspec_wbsFast";
    }
    if(backend == "wbsFast2") {
        spec_filename = "name_confilspec_wbsFast2";
    }
    {double,string}[] result = ConfigurationReader(spec_filename,["wbsh_offset1","wbsh_width1","wbsh_offset2","wbsh_width2","wbsh_offset3","wbsh_width3","wbsh_offset4","wbsh_width4","wbsv_offset1","wbsv_width1","wbsv_offset2","wbsv_width2","wbsv_offset3","wbsv_width3","wbsv_offset4","wbsv_width4","hrsh_sel","hrsv_sel"],band,0.0);
    int wbsh_offset1 = iround(result[0]{0});
    int wbsh_width1 = iround(result[1]{0});
    int wbsh_offset2 = iround(result[2]{0});
    int wbsh_width2 = iround(result[3]{0});
    int wbsh_offset3 = iround(result[4]{0});
    int wbsh_width3 = iround(result[5]{0});
    int wbsh_offset4 = iround(result[6]{0});
    int wbsh_width4 = iround(result[7]{0});
    int wbsv_offset1 = iround(result[8]{0});
    int wbsv_width1 = iround(result[9]{0});
    int wbsv_offset2 = iround(result[10]{0});
    int wbsv_width2 = iround(result[11]{0});
    int wbsv_offset3 = iround(result[12]{0});
    int wbsv_width3 = iround(result[13]{0});
    int wbsv_offset4 = iround(result[14]{0});
    int wbsv_width4 = iround(result[15]{0});
    int hrsh_sel = iround(result[16]{0});
    int hrsv_sel = iround(result[17]{0});
    //HRS settings:
    //1. Translate HRS selection code into array of sub-band state
    //Check against conversion table
    //H-polar    
    result = ConfigurationReader("name_hrs_select",["band1","band2","band3","band4"],"0",double(hrsh_sel));
    bool[] band_hrsh = [true,true,true,true];
    for(int i = 0 .. 3) {
        if(result[i]{0} == 0.0) {
            band_hrsh[i] = false;
        }
    }
    //V-polar
    result = ConfigurationReader("name_hrs_select",["band1","band2","band3","band4"],"0",double(hrsv_sel));
    bool[] band_hrsv = [true,true,true,true];
    for(int k = 0 .. 3) {
        if(result[k]{0} == 0.0) {
            band_hrsv[k] = false;
        }
    }
    //2. Convert resolution code
    int hrsh_res = 3;
    //wb
    int hrsv_res = 3;
    //wb
    //H-polar
    if(hrs_mode[0] == "hr") {
        // high resolution
        hrsh_res = 0;
    }
    if(hrs_mode[0] == "mr") {
        // low resolution
        hrsh_res = 1;
    }
    if(hrs_mode[0] == "lr") {
        // low resolution
        hrsh_res = 2;
    }
    //V-polar
    if(hrs_mode[1] == "hr") {
        // high resolution
        hrsv_res = 0;
    }
    if(hrs_mode[1] == "mr") {
        // low resolution
        hrsv_res = 1;
    }
    if(hrs_mode[1] == "lr") {
        // low resolution
        hrsv_res = 2;
    }
    //Check whether a given HRS polar is in use: it is so unless sel. code is 0
    bool hrsh_used = true;
    bool hrsv_used = true;
    if(hrsh_sel == 0) {
        hrsh_used = false;
    }
    if(hrsv_sel == 0) {
        hrsv_used = false;
    }
    //
    //Other check is whether HRS is used at all
    if(backend == "wbs") {
        hrsh_used = false;
        hrsv_used = false;
        band_hrsh = [false,false,false,false];
        band_hrsv = [false,false,false,false];
    }
    //
    //Case of hrsFast: use only half of the so-far selected sub-band
    //
    if(backend == "hrsFast") {
        if(hrs_mode[0] == "hr" || hrs_mode[1] == "hr") {
            error("hrsFast cannot be used with high resolution mode.");
        }
        //Selection code will depend on resolution mode:
        //We use the same mapping of the band for all cases.
        //1. If wide-band mode: we had 8 sub-bands, keep 4 in 2 pairs: 1L/U and 2L/U
        //   widebits=[192,12,3,48] -> sel=195
        //2. If lr mode: We had 4 sub-bands: 1U,3U,4L and 2L. We keep 1U and 3U
        //   lowbits=[192,12,48,3] -> sel=240
        //3. If mr mode: We had 2 sub-bands 1U and 4L. We keep 1U
        //   normalbits=[240,15] -> sel=240
        band_hrsh = [true,true,false,false];
        band_hrsv = [true,true,false,false];
        //For mr, we need to keep only the first half
        if(hrs_mode[0] == "mr") {
            band_hrsh = [true,false,true,false];
        }
        if(hrs_mode[1] == "mr") {
            band_hrsv = [true,false,true,false];
        }
    }
    //WBS
    //1. WBS channels in use
    int[] wbsh_ch1 = [wbsh_offset1,wbsh_offset1 + wbsh_width1];
    int[] wbsh_ch2 = [wbsh_offset2 - 2048,wbsh_offset2 + wbsh_width2 - 2048];
    int[] wbsh_ch3 = [wbsh_offset3 - 4096,wbsh_offset3 + wbsh_width3 - 4096];
    int[] wbsh_ch4 = [wbsh_offset4 - 6144,wbsh_offset4 + wbsh_width4 - 6144];
    int[] wbsv_ch1 = [wbsv_offset1,wbsv_offset1 + wbsv_width1];
    int[] wbsv_ch2 = [wbsv_offset2 - 2048,wbsv_offset2 + wbsv_width2 - 2048];
    int[] wbsv_ch3 = [wbsv_offset3 - 4096,wbsv_offset3 + wbsv_width3 - 4096];
    int[] wbsv_ch4 = [wbsv_offset4 - 6144,wbsv_offset4 + wbsv_width4 - 6144];
    //
    //2. Other check is whether WBS is used at all
    bool wbsh_used = true;
    bool wbsv_used = true;
    if(backend == "hrs" || backend == "hrsFast") {
        wbsh_used = false;
        wbsv_used = false;
    }
    //Build up backend parameter tupple
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrsh_used,hrsh_res,band_hrsh},{hrsv_used,hrsv_res,band_hrsv},{wbsh_used,[wbsh_ch1,wbsh_ch2,wbsh_ch3,wbsh_ch4]},{wbsv_used,[wbsv_ch1,wbsv_ch2,wbsv_ch3,wbsv_ch4]}};
    // Readout parameters for HRS1,HRS2, WBS1,WBS2

    return backendreadoutparms;
}

// Load boot in rescue mode, mode
mode HifiManCmd_load_boot {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    Mode_status_check_rescue("normal");
    //StartMode_block_ops();
    mois_comment("Start loading and booting of a new OBSW in rescue mode");
    Load_boot_block_ops();
    //
    //Get applicable HK rate
    {double,string}[] result = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    double hk_rate = result[0]{0};
    //
    mois_step("Adjust HK data rate.");
    HKrate_block_ops(hk_rate);
    Mode_status_check_intermediate();
    StopMode_block_ops();
}

////////////////////////////////////
// Routine to provide initial guesses for sequence parameters
// Position switch observing mode
//
{string,double,double}[] procedure HifiPointProcPositionSwitchSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,5]; // data dump interval limited by the data rates
    int n_int_on = 3 in [2,1800]; // number of data dumps for integration per phase
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // Compute derived quantities
    int int_time_guess = imax(iceil(0.3 * allan_time_lores),datalimit);
    int data_time_guess = imin(5,int_time_guess);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_int_on_guess = imax(int_time_guess / data_time_guess,2);
    int n_int_on_range = 2 - n_int_on_guess;
    if(n_int_on_range == 0) {
        n_int_on_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,n_int_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    // Contruct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_int_on",double(n_int_on_guess),double(n_int_on_range)}];

    return retvalues;
}

// Set diplexer currents for both polarizations, procedure
procedure Set_Diplexer_current_proc_fm {
    double dipl_curr_h = 1.0; //Diplexer current H polarization
    double dipl_curr_v = 1.0; //Diplexer current V polarization
}{
    Hifi_HIFI_CH1_DPACT_C($BBID,dipl_curr_h);
    Hifi_HIFI_CV1_DPACT_C($BBID,dipl_curr_v);
    delay(1);
}

/////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing for a
// Spectral Scan Frequency-Switch observing mode
// 
// We assume that each telescope motion is related to an
// instrument calibration.
// 
{{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} procedure SScanFSwitch_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq_low = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4; // Frequency scan redundancy
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_chop_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_chop_off = 1 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Create composite readout structure for backends
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get frequency grid characteristic parameters
    {int,double,double[],int[][],int,bool} fqparms = MakeFreqGrid(band,lo_freq_low,lo_freq_up,redundancy,freq_throw,n_freq_point);
    double reffreq = fqparms{1};
    double[] freqgrid = fqparms{2};
    int[][] grouporder = fqparms{3};
    // Process tuning level grid
    double[][] levelgrid = GetSScanLevelGrid(band,wbs1,wbs2,freqgrid,fqparms{0},grouporder);
    {bool,double[]} targets = TargetLevels(band,reffreq,levelgrid);
    bool retuning = targets{0};
    double[] targetgrid = targets{1};
    string reftarget = "";
    if(retuning) {
        reftarget = "sscan_normal";
    }
    {int,double,double[],int[][],bool,double[],int,bool} spectralparms = {fqparms{0},reffreq,freqgrid,grouporder,retuning,targetgrid,fqparms{4},fqparms{5}};
    //////////////////////////////////////////////////////////////////////
    // Get timing within the normal frequency-switch observations
    int readoutdead = SlowChopReadoutDelay(band,reffreq,backendreadoutparms);
    int jitterdead = GetMaxTimeJitter(band,reffreq);
    // Integration time per frequency and pointing
    int on_inttime = 2 * n_chop_on * data_time;
    int off_inttime = 2 * n_chop_off * data_time_off;
    // Duration of initial set up
    // Staying at the same frequency makes no sense here. 
    // First frequency point
    double runningfreq = freqgrid[grouporder[1][0]];
    // Compute load integration time
    int loadlength = duration(SScanDoubleLoadMeasurement(band,runningfreq,reffreq,freq_throw,true,eff_resolution{0},data_time,backendreadoutparms));
    loadlength = loadlength + readoutdead;
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFIFsw(band,runningfreq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},"sscan_normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,runningfreq,true);
    }
    initlength = initlength + loadlength;
    // recompute load length during slews  - no retuning 
    loadlength = duration(SScanDoubleLoadMeasurement(band,reffreq,reffreq,freq_throw,false,eff_resolution{0},data_time,backendreadoutparms));
    loadlength = loadlength + readoutdead;
    // Check load spacing
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    // Tuning delays
    int bigtunestep = duration(HIFIRetuneFsw(band,reffreq,freq_throw,reftarget));
    // Correct for variation within the band
    int tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq);
    bigtunestep = bigtunestep + 2 * tunediff;
    // As step within a group could be faster than a large step 
    if(n_freq_point > 1) {
        int smallstep = duration(HIFIChangeFreqFsw(band,reffreq,freq_throw));
    } else {
        smallstep = bigtunestep;
    }
    // For double phases I can use the added jitterdead in both phases for tune
    int auxtunestep = bigtunestep - jitterdead;
    int halftunestep = (auxtunestep + 1) / 2;
    // Telescope pointing
    int on_pointing = n_freq_point * on_inttime + (n_freq_point - 1) * smallstep + halftunestep + jitterdead;
    int off_pointing = off_inttime + halftunestep + jitterdead;
    // Check load_interval allowance
    int scan_time = 2 * imax(on_pointing,off_pointing);
    if(scan_time > load_spacing) {
        SError("Load interval of " + load_interval + "s is exceeded by " + n_chop_on * n_freq_point + " chop cycles.");
    }
    // Estimate of the load-cycles to issue a representative 
    // telescope command
    if(n_cycles > 1) {
        // How often do I have to perform a load slew
        int n_loadinterval = imax(load_interval / scan_time,1);
        // fit with n_cycles
        n_loadinterval = imin(n_loadinterval,n_cycles);
        n_loadinterval = IMultiple(n_loadinterval,n_cycles);
    } else {
        n_loadinterval = 1;
    }
    // No dangling needed in this mode - we stop halftunelength before telescope
    int dangling = 0;
    bool end_load_on = false;
    bool end_load_off = false;
    // Return all the times needed for telescope call and post_timing processing

    return {{on_inttime,off_inttime,on_pointing,off_pointing,loadlength,auxtunestep,load_spacing,n_loadinterval,n_chop_on,n_chop_off,data_time,data_time_off,end_load_on,end_load_off,initlength,dangling},spectralparms};
}

// Set diplexer currents for both polarizations, block
block Set_Diplexer_current_FSW_block_fm HIFI 3743 {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 522.0; //The LO frequency in GHz 
}{
    //Start_block();
    if(band == "3a" || band == "3b" || band == "4a" || band == "4b" || band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        Hifi_HIFI_CH1_DPACT_C($BBID,result_dip[0]);
        Hifi_HIFI_CV1_DPACT_C($BBID,result_dip[1]);
    }
    delay(1);
}

//////////////////////////////////////////////////////////////////////////
// Procedure to generate the telescope command for the OTF observing mode
{int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,int} procedure OTFDoubleChopNoRef_telescope {
    int naifid = 0; // Tracking object ID
    {double,double} mapcenter = {0.0,0.0}; // Coordinates of the center of the map
    {double,double} linedistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1; // Number of rows in the map
    double linesize = 0.0050 in [0.0,2.0]; // Length of OTF lines
    double scanvelocity = 4.0E-4 in [2.75E-5,0.017]; // Scan velocity in � per s
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int n_cover = 1; // Number of map coverages
    {int,int,int,int,bool,int,int} timing = {21,1780,1,21,false,50,0}; // timing parameter list
}{
    // Assign values
    int holdlength = timing{3};
    // Load duration - turn around time
    int n_loadinterval = timing{2};
    // N of OTF scans between load measurements
    int initlength = timing{5};
    // Initial setup time
    int dangling = timing{6};
    // Final load measurement
    // no load means n_loadinterval=0 here
    int nlines_tot = nlines * n_cover;
    if(n_loadinterval > nlines_tot) {
        int n_linesperscan = 0;
    } else {
        n_linesperscan = n_loadinterval;
    }
    // Create variables for telescope command
    string ib = GetBoresight(band,lo_freq,false);
    double ra = mapcenter{0};
    double dec = mapcenter{1};
    double patt = AngleFromVector(linedistance);
    patt = RotateRight(patt);
    // I assume that ValidMapSize was called, so that the API granularity
    // is meet for d1 and rate
    double d1 = linesize * 3600.0;
    double rate = scanvelocity * 3600.0;
    // Granularity for d2
    double linestep = 0.5;
    double d2_req = AngleVectorLength(linedistance);
    d2_req = d2_req * 3600.0;
    // Define maximum reduction
    double eps = 0.98;
    double d2 = double(iceil(d2_req * eps / linestep)) * linestep;
    // Exception for the "impossible" case of spacings below 2arcsec
    d2 = max(d2,2.0);
    // Check parameter compatibility with pointing command for parameters
    // which are no direct input parameters
    if(rate > 60.0) {
        IError("Maximum scan velocity exceeded. Reduce the step size.");
    } else {
        if(rate < 0.1) {
            SError("Minimum scan velocity not reached. Reduce switch cycle number.");
        }
    }
    if(d1 > 7200.0) {
        IError("OTF line length too long. Reduce the map size.");
    }
    if(d2 > 480.0) {
        IError("OTF line spacing too coarse. Increase the sampling.");
    }
    // repetition at multiple frequencies not yet implemented:
    int n_repeat = n_cover;
    // return parameters in required order

    return {initlength,0,dangling,ib,naifid,ra,dec,true,patt,0.0,0.0,nlines,d1,d2,rate,holdlength,n_linesperscan,n_repeat};
}

//Procedure checking the consistency of total power spectroscopy
//parameters to be sent to configuration command.
bool procedure Check_total_power_parameters_proc {
    int n_wbs_start = 1; //Nb of frames
    int r_hrs = 1; //Nb of HRS readout per WBS readout
    int n_wbs_integr = 1; //Number of wbs readout packetized per WBS frame
    int n_hrs_integr = 1; //Number of hrs readout packetized per HRS frame
    int del_hrs = 5; //Delay before starting HRS integration
    int del_wbs = 5; //Delay before starting WBS integration
    int t_acc_wbs = 4005; //Duration of WBS frame 
    int t_acc_hrs = 1950; //Duration of HRS frame
    int wbsh_offset1 = 0;
    int wbsh_width1 = 2048;
    int wbsh_offset2 = 2048;
    int wbsh_width2 = 2048;
    int wbsh_offset3 = 4096;
    int wbsh_width3 = 2048;
    int wbsh_offset4 = 6144;
    int wbsh_width4 = 2048;
    int wbsv_offset1 = 0;
    int wbsv_width1 = 2048;
    int wbsv_offset2 = 2048;
    int wbsv_width2 = 2048;
    int wbsv_offset3 = 4096;
    int wbsv_width3 = 2048;
    int wbsv_offset4 = 6144;
    int wbsv_width4 = 2048;
    int hrs_rshift = 0; //HRS bit shift
    int wbs_rshift = 0; //WBS bit shift
    int hrsh_sel = 255; //HRS-H band selection
    int hrsv_sel = 255; //HRS-V band selection
    string wbs_packing = "24_bits_format";
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    error("Procedure Check_total_power_parameters_proc is not used anymore.");

    return false;
}

/////////////////////////////////////////////////////////////////
// Procedures to compute the WBS IF levels for spectral scans
//
// Read attenuators settings across a spectral scan
double[][] procedure GetSScanLevels {
    string band = "4a"; // HIFI band
    double[] freqgrid = [978053.7,978301.8,978381.1]; // frequency grid
    int[] subbandindices = [0,1,2,3,4,5,6,7]; // WBS subbands actually used
}{
    // Go select subband attenuators to read
    string[] subbandnames = ["pow_hw1","pow_hw2","pow_hw3","pow_hw4","pow_vw1","pow_vw2","pow_vw3","pow_vw4"];
    int nsub = length(subbandindices);
    string[] bandnames = [];
    for(int j = 0 .. nsub - 1) {
        bandnames[j] = subbandnames[subbandindices[j]];
    }
    // Initialize output grid
    double[][] attgrid = [[]];
    double[] hlpgrid = [];
    int nel = length(freqgrid);
    // Go through frequency grid and read attenuators
    for(int i = 0 .. nel - 1) {
        double lo_freq = freqgrid[i];
        double[] atts = CalibrationReader("power_levels",bandnames,band,lo_freq);
        attgrid[i] = clone(atts);
    }

    return attgrid;
}

// Patch OBSW in intermediate mode, mode
mode HifiManCmd_patch_OBSW {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    Mode_status_check_intermediate();
    StartMode_block_ops();
    mois_comment("Start patching of the OBSW in intermediate mode");
    Patch_OBSW_block_ops();
    StopMode_block_ops();
}

//HIFI LO tuning, procedure
//Target current is read from look-up table
procedure LO_tuning_w_mixerchoice_proc {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string mixer_polarization = "H" in ["H","V","B"]; //The polarization to be used for the tuning
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Get target mixer current
    {double,string}[] result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double middle_d2 = result[0]{0};
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    //
    //delay(5);	//to settle at this value
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//////////////////////////////////////////////////////////////////////////
// Procedure to generate the telescope command for the OTF observing mode
{int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,double,double,int,int,int,int,int} procedure OTFmap_telescope {
    int naifid = 0; // Tracking object ID
    {double,double} mapcenter = {0.0,0.0}; // Coordinates of the center of the map
    {double,double} linedistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines_tot = 1; // Number of rows in the map
    double linesize = 0.0050 in [0.0,2.0]; // Length of OTF lines
    {double,double} offposition = {0.2,0.2}; // Coordinates of the OFF position
    double scanvelocity = 4.0E-4 in [2.75E-5,0.017]; // Scan velocity in � per s
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int n_linesperscan = 1; // Number of lines between two OFFs
    int n_cover = 1; // Number of map coverages
    {int,int,int,int,int,int,int,int} timing = {10,1,12,13,21,10,50,0}; // timing parameter list
}{
    // Assign values
    int off_inttime = timing{3};
    // Length of OFF integration
    int loadlength = timing{4};
    // Load duration
    int n_loadinterval = timing{5};
    // N of OTF scans between load measurements
    int initlength = timing{6};
    // Initial setup time
    int dangling = timing{7};
    // Final hold
    // Create variables for telescope command
    string ib = GetBoresight(band,lo_freq,false);
    // A change of ra-dec depending on naifid may be needed
    double ra = mapcenter{0};
    double dec = mapcenter{1};
    double raoff = offposition{0};
    double decoff = offposition{1};
    double patt = AngleFromVector(linedistance);
    patt = RotateRight(patt);
    // I assume that ValidMapSize was called, so that the API granularity
    // is meet for d1 and rate (should rather be done in HSPOT)
    double d1 = linesize * 3600.0;
    double rate = scanvelocity * 3600.0;
    // Separate treatment of repeated scans of the same line
    if(nlines_tot == 1) {
        int n_lines_eff = n_linesperscan;
        double d2 = 0.0;
    } else {
        n_lines_eff = nlines_tot;
        // Granularity for d2
        double linestep = 0.5;
        double d2_req = AngleVectorLength(linedistance);
        d2_req = d2_req * 3600.0;
        // Define maximum reduction
        double eps = 0.98;
        d2 = double(iceil(d2_req * eps / linestep)) * linestep;
        // Exception for the "impossible" case of spacings below 2arcsec
        d2 = max(d2,2.0);
    }
    // Check parameter compatibility with pointing command for parameters
    // which are no direct input parameters
    if(rate > 60.0) {
        IError("Maximum scan velocity exceeded. Reduce the step size.");
    } else {
        if(rate < 0.1) {
            SError("Minimum scan velocity not reached. Reduce the supersampling.");
        }
    }
    if(d1 > 7200.0) {
        IError("OTF line length too long. Reduce the map size.");
    }
    if(d2 > 480.0) {
        IError("OTF line spacing too coarse. Increase the sampling.");
    }
    // We already put harder constrains on some parameters than required
    // by the pointing commands:
    // n_lines_eff <= 240 (HIFI), <= 1500(MPS)
    // n_linesperscan*j = n_lines_eff (HIFI), n_linesperscan <= n_lines_eff (MPS)
    //
    // repetition at multiple frequencies not yet implemented:
    int thold = 0;
    int nhold = 0;
    int n_repeat = n_cover;
    // return parameters in required order

    return {initlength,0,dangling,ib,naifid,ra,dec,true,patt,0.0,0.0,n_lines_eff,d1,d2,rate,n_linesperscan,off_inttime,raoff,decoff,n_repeat,thold,nhold,loadlength,n_loadinterval};
}

// Slow chop
procedure HIFI_Spectr_slow_chop_proc_aot {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    string[] phases = ["chop_M3left","chop_M3right"]; // identifiers for chopper positions
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    //Get appropriate chopper voltages
    {bool,double,double} chopparms = GetChopVoltages(band,lo_freq,phases[0],phases[1]);
    bool isPrime = chopparms{0};
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    // Call command
    if(isPrime) {
        Hifi_HIFI_P_Spectr_slow_chop($BBID,chopparms{1},chopparms{2});
    } else {
        Hifi_HIFI_R_Spectr_slow_chop($BBID,chopparms{1},chopparms{2});
    }
    delay(2 * n_cycle * data_time);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// IV curve, block
block IVcurve_raw_fm HIFI 3211 {
    string band = "1a";
}{
    //Start_block() ;   
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["bias_min_h","bias_max_h","bias_steps_h","bias_min_v","bias_max_v","bias_steps_v"],band,0.0);
    //H polar
    double bias_min_h = result_d[0]{0};
    double bias_max_h = result_d[1]{0};
    int steps_h = iround(result_d[2]{0});
    //V polar
    double bias_min_v = result_d[3]{0};
    double bias_max_v = result_d[4]{0};
    int steps_v = iround(result_d[5]{0});
    //Bias to set at end of IVC
    //Need a representative frequency: take keyfreq
    double[] result = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result[0];
    //
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v","norm_magn_h","norm_magn_v"],band,lo_freq);
    double bias_h = result_d[0]{0};
    double bias_v = result_d[1]{0};
    //Fetch magnets only if band is not band6
    double magnetcurrent_h = 0.0;
    double magnetcurrent_v = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        magnetcurrent_h = result_d[2]{0};
        magnetcurrent_v = result_d[3]{0};
    }
    //The IVCurve is done on the smallest range and the finest step
    double bias_min = max(bias_min_h,bias_min_v);
    double bias_max = min(bias_max_h,bias_max_v);
    int steps = iround(max(double(steps_h),double(steps_v)));
    //
    //First set magnets to max.
    double magnet_current_max_h = 0.0;
    double magnet_current_max_v = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
        magnet_current_max_h = result_d[0]{0};
        magnet_current_max_v = result_d[1]{0};
    }
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_current_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_current_max_v);
    delay(1);
    //Perform IV curve
    IVcurve(band,bias_min,bias_max,steps,magnetcurrent_h,magnetcurrent_v,bias_h,bias_v);
}

// Chop between the two internal loads, block
// We take 1 spectrum per phase.
block Stability_intcold_inthot_fm HIFI 3423 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integration pairs
    int integ_time = 4; //Total (co-added) integration time of ONE SINGLE phase in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "slowchop" in ["slowchop","fastchop"]; //Whether to use slowchop or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    Start_block();
    double chop = 0.0;
    //Get chopper settings
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_hot","chop_cold"],band,0.0);
    double chop_hot = result[0]{0};
    double chop_cold = result[1]{0};
    //
    //We implement a special slow-chop spectroscopy between
    //internal cold and external cold
    if(chopmode == "slowchop") {
        Slow_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_hot,chop_cold);
    } else {
        Fast_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_hot,chop_cold,chop_phase);
    }
}

//Chopper rotation procedure. It takes into account
//overshoot risk and performs the rotation in
//2 steps if the targetted positions are either of the end stops
procedure Chopper_Rotation_proc_fm {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string chop_current_position = "chop_hot_ang"; //Current chopper position
    string chop_target_position = "chop_cold_ang"; //Targetted chopper position
}{
    //Retrieve angles of corresponding positions
    {double,string}[] result_d = ConfigurationReader("name_chopper",[chop_current_position,chop_target_position,"chop_endstopright_ang","chop_endstopleft_ang","overshoot"],band,0.0);
    double chop_current_angle = result_d[0]{0};
    double chop_target_angle = result_d[1]{0};
    double chop_endstopright_angle = result_d[2]{0};
    double chop_endstopleft_angle = result_d[3]{0};
    double overshoot = result_d[4]{0};
    string chop_target_name = result_d[1]{1};
    string chop_current_name = result_d[0]{1};
    int step = 1;
    //
    //Check whether the rotation may reach either of the end stops, i.e.
    //go beyond either the HBB or M3_left
    ///// We suppose here overshoot to be 0, so the 2 steps only occur when targetting
    ///// the end stops strictly.
    double total_angle = abs(chop_target_angle - chop_current_angle) * (1.0 + overshoot);
    //
    //The endstop that one may hit depends on the rotating direction
    //Case were endstop is the left one
    double angle_to_endstop = abs(chop_endstopleft_angle - chop_current_angle);
    if(chop_target_angle > chop_current_angle) {
        //then end stop is the right one
        angle_to_endstop = abs(chop_endstopright_angle - chop_current_angle);
    }
    //debug_print(total_angle);
    //debug_print(angle_to_endstop);
    if(total_angle >= angle_to_endstop) {
        message("Chopper expected to hit the endstop. Rotation done in two steps");
        step = 2;
    }
    //If we have two steps necessary, the middle position between current and
    //targetted position is used.
    result_d = ConfigurationReader("name_confilfpu",[chop_target_name,chop_current_name],band,0.0);
    double chop = result_d[0]{0};
    double chop_intermediate = (result_d[0]{0} + result_d[1]{0}) / 2.0;
    //
    //Check whether sent values need to be converted in case of redundant mode
    chop = Check_Chopper_Prime_Redundant(chop);
    //
    if(step == 1) {
        HIFI_CPR_Chopper_Rot_proc_fm(chop);
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent voltage
        delay(1);
    }
    if(step == 2) {
        chop_intermediate = Check_Chopper_Prime_Redundant(chop_intermediate);
        HIFI_CPR_Chopper_Rot_proc_fm(chop_intermediate);
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent voltage
        delay(1);
        HIFI_CPR_Chopper_Rot_proc_fm(chop);
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent voltage
        delay(1);
    }
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of peakup observing mode
{int,{int,int,int,int,int,double,int,int}} procedure Peakup_post_timing {
    {int,int,int,int,int,double,int,int} pre_timing = {8,10,2,21,4,1.6,50,0}; // pre timing parameter list  
    int[] telescopetimes = [300,180,10,10,29,0];
    int nlines_tot = 3; // Number of rows in the map
    int npoints = 3; // Number of points per row
}{
    // Get all values from the pre_timing section
    int inttime = pre_timing{0};
    int pointing = pre_timing{1};
    int data_time = pre_timing{2};
    int loadlength = pre_timing{3};
    int n_chop = pre_timing{4};
    double eff_resolution = pre_timing{5};
    int initlength = pre_timing{6};
    int dangling = pre_timing{7};
    // Get all values from the telescope section  
    int telinit = telescopetimes[1];
    // Initial slew time
    int slewtime = telescopetimes[2];
    // Slew time to next point
    int slewline = telescopetimes[3];
    int tend = telescopetimes[5];
    // Total number of scans
    int n_tot = npoints * nlines_tot;
    ///////////////////////
    // obtain all slew durations
    int tinlinesdead = (npoints - 1) * slewtime * nlines_tot;
    int toutlinesdead = (nlines_tot - 1) * slewline;
    // Compute total duration
    int totaltime = n_tot * pointing + tinlinesdead + toutlinesdead;
    // Add dangling time if not included in pointing
    // Add time needed to perform AOCS correction
    int closelength = duration(HIFICloseObs()) + duration(HifiPeakupCorrection());
    dangling = imax(dangling + closelength - tend,0);
    totaltime = totaltime + dangling + tend;
    // show gyro-propagation messages
    GCPMessages(pointing,totaltime,tend);
    // Return all the times needed in the observing mode modules

    return {totaltime,{inttime,pointing,data_time,loadlength,n_chop,eff_resolution,initlength,dangling}};
}

/////////////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the OTF observing mode
{double,double,double,double,double} procedure OTFFSwitch_noisecomputer {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    int nlines_tot = 1; // Number of rows in the map
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int n_switch_on = 1; // Supersamplingfactor
    int n_linesperscan = 2; // Number of lines between two OFFs
    int off_inttime = 16; // Integration time per OFF phase
    int n_cycles = 1; // Number of map coverages
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double,double,double} tact = {10.0,4.9,4.9,0.05,0.05}; // Field of actual dead and integration times
}{
    // The sum of drift noise and radiometric noise is computed.
    //
    double tdead = tact{0};
    // Average total dead time in one scan
    double inttimeperonphase = tact{1};
    // Actual integration time in ON phase
    double inttimeperoffphase = tact{2};
    // Actual integration time in OFF phase
    double deadtimeperonphase = tact{3};
    // Dead time per switch phase on ON
    // Get parameters which are needed
    double tsys = InterpolateTsys(band,lo_freq);
    double eta_mb = InterpolateCoupling(band,lo_freq);
    double[] gssb = InterpolateGssb(band,lo_freq);
    // Get the drift parameters to compute the drift noise
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double allan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // Differential Allan variance
    allanparms = InterpolateSpecFSwitchAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double dalpha = allanparms[1];
    binningexp = 1.0 / allanparms[2];
    double dallan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double dallan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // resolution of OFF phase
    double sw_resolution = GetFSwitchSWResolution(band,lo_freq);
    double sw_resolution_lores = max(eff_resolution{1},sw_resolution);
    double sw_resolution_hires = max(eff_resolution{0},sw_resolution);
    // !!!! The computation of the noise is formally NOT CORRECT for this 
    // !!!! case. For simplicity we use as a rough approximations the equations
    // !!!! for a double-difference setup instead of a difference with 
    // !!!! OTF scheme !!!
    // Compute the relative noise for the detailed timing
    double on_int = double(2 * data_time * n_switch_on);
    // correct for double scan - treat like integrated in one go
    if(nlines_tot == 1 && n_linesperscan > 1) {
        on_int = on_int * double(n_linesperscan);
    }
    // fudge factor to taking OFF interpolation into account
    double off_int = double(off_inttime) * 1.5;
    // The dead time per switch might deviate between ON and OFF - ignored
    double deadtimeperswitch = deadtimeperonphase;
    // Dead time includes other points, but excludes off_int fudging
    // This is slightly too small (excludes inner point dead time) - ignored
    double tdiff = max(tscan - on_int - off_int,0.0);
    // Get actual noise
    // This is returned twice: for both limiting resolutions
    double systemnoise_lores = DoubleDifferenceNoise(inttimeperonphase / allan_time_lores,[inttimeperoffphase / inttimeperonphase,sw_resolution_lores / eff_resolution{1},on_int / allan_time_lores,off_int / allan_time_lores,deadtimeperswitch / allan_time_lores,tdiff / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    double systemnoise_hires = DoubleDifferenceNoise(inttimeperonphase / allan_time_hires,[inttimeperoffphase / inttimeperonphase,sw_resolution_hires / eff_resolution{0},on_int / allan_time_hires,off_int / allan_time_hires,deadtimeperswitch / allan_time_hires,tdiff / allan_time_hires,alpha,dallan_time_hires / allan_time_hires,dalpha]);
    double noiseratio = DoubleDifferenceNoiseRatio(inttimeperonphase / allan_time_lores,[inttimeperoffphase / inttimeperonphase,sw_resolution_lores / eff_resolution{1},on_int / allan_time_lores,off_int / allan_time_lores,deadtimeperswitch / allan_time_lores,tdiff / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    // Compute total double sideband noise 
    // Correct for signal in both pases
    double dsbnoise_lores = tsys * sqrt(systemnoise_lores / (eff_resolution{1} * 2000000.0 * double(n_cycles) * tscan));
    double dsbnoise_hires = tsys * sqrt(systemnoise_hires / (eff_resolution{0} * 2000000.0 * double(n_cycles) * tscan));
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Get single sideband noise equivalent
    double usbnoise_lores = dsbnoise_lores / gssb[0];
    double usbnoise_hires = dsbnoise_hires / gssb[0];
    double lsbnoise_lores = dsbnoise_lores / gssb[1];
    double lsbnoise_hires = dsbnoise_hires / gssb[1];
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiseratio};
}

//!!!!!!!!!!!!!!!!!!!!
// Associated blocks
//!!!!!!!!!!!!!!!!!!!!
// LO settling time for a LO sub-band change, 1st block
// Block for first tuning
block LO_Settling_time_first_tuning_fm HIFI 3680 {
    string band_a = "1a" in ["1a","2a","3a","4a","5a","6a","7a"]; // HIFI band a
    int int_time1 = 3600; //Integration time after first tuning
    double lo_freq_a = 500.0; //LO frequency in sub-band a
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //
    //Init and tune of LO: configuration from safe to tuned.
    LCU_config_nominal_proc_fm(band_a,lo_freq_a);
    LO_tuning_w_mixerchoice_proc(band_a,lo_freq_a,"H");
    //
    //Configure spectroscopy integration
    Configure_Spectrometer_proc_fm(band_a,int_time1,["wb1","wb1"],backend);
    //4 sec. integration
    //Take series of spectra during int_time1 seconds
    HIFI_Spectr_total_power_proc_fm(band_a,backend,int_time1);
    //
    //Now switch off LO sub-band
    LCU_switch_off_proc_fm();
}

//HIFI vector scan, block for experts: allow all vector scan parameters as user input
//Check vector scan with some default parameters
block Vector_scan_EXPERT_block_fm HIFI 3671 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    double step_drain2_v = 0.05; //D2_V steps during vector scan
    int nsteps = 10; //Number of steps. Should not be larger than 10
    double step_time = 1.0; //In seconds.
    double drain2_v_start = 1.5; //Starting D2_V in vector scan
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    //double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlcu,["drain2_v"],band,lo_freq);
    double drain2_safe = result[0]{0};
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    //double step_drain2_v = result[0]{0};
    //int nsteps = iround(result[1]{0});
    //double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    //delay(1);
    //Execute vector scan 
    Hifi_HIFI_vector_scan($BBID);
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

////////////////////////////////////
// OTF load-chop observing mode
// 
{string,double,double}[] procedure HifiMappingProcLoadChopOTFSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints = 10 in [1,720]; // Number of data dumps per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    {double,double,double,double} phaselengths = LoadChopPhaseLengths(band,lo_freq,effResolution,oneGHzReference);
    // Compute derived quantities
    // Main loop
    int main_phase = iceil(phaselengths{0});
    // How many lines could we do at most?
    int n_linesperscan_guess = main_phase / (2 * datalimit) + 1;
    n_linesperscan_guess = imax(n_linesperscan_guess * n_linesperscan_guess / npoints,1);
    // restrict the scan size
    if(nlines == 1 && n_linesperscan_guess > 1) {
        n_linesperscan_guess = 2;
    } else {
        n_linesperscan_guess = IMultiple(n_linesperscan_guess,nlines);
        n_linesperscan_guess = imin(n_linesperscan_guess,nlines);
    }
    int n_linesperscan_range = 1 - n_linesperscan_guess;
    if(n_linesperscan_range == 0) {
        n_linesperscan_range = 1;
    }
    double n_pointsperscan = double(n_linesperscan * npoints);
    // Compute back
    int int_time_guess = main_phase / iceil(sqrt(n_pointsperscan));
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int n_switch_on_guess = imax(int_time_guess / (2 * data_time_guess),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    data_time_guess = imax(imin(5,int_time_guess / (2 * n_switch_on_guess)),datalimit);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) * 0.67 * sqrt(n_pointsperscan) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)},{"n_linesperscan",double(n_linesperscan_guess),double(n_linesperscan_range)}];

    return retvalues;
}

//////////////////////////////////////////////
// Testmodes for TV specific activities
// They are usually concatenation of 
// existing modules, here gathered for
// a simpler execution
//
//
// DT - 08-02-08: first version
//////////////////////////////////////////////
//modes: see fm_testmodes.cus
////////////////////////////////////
//Special blocks taken from MOC_CUS
////////////////////////////////////
// Diplexer calibration for a given mixer band
// uses a list of pre-defined frequencies where to measure
// the diplexer scan.
procedure Diplexer_survey_proc_TV {
    string band = "3a" in ["3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI band
}{
    //
    //Get the list of frequencies to be used for the scan
    string tab = "config_dipscan_TV.config";
    double bandnb = GetBandCode(band);
    double lofreqlow = dlookup(tab,"" + iceil(bandnb),"lofreqlow");
    double lofreqhigh = dlookup(tab,"" + iceil(bandnb),"lofreqhigh");
    double lofreqstep = dlookup(tab,"" + iceil(bandnb),"lofreqstep");
    //
    LCU_switchon_proc_fm(band);
    //Wait an extra delay of 1 min for short term stabilization
    delay(60);
    //
    //Start loop on diplexer scans
    double current_LO = lofreqlow;
    bool endreached = false;
    //Loop on key frequencies per LO band
    while(current_LO <= lofreqhigh && endreached == false) {
        Check_Band_vs_Freq_proc_fm(band,current_LO);
        //Configure FPU at that frequency
        Init_MSA_HBB_fm(band,"CLOSE",current_LO,"ON");
        //Perform LO tuning at that frequency
        //This needs to be done at 0.6mV bias due to Imix target
        LO_tuning_block_fm(band,current_LO);
        //
        //Prepare for diplexer scan
        //In case of band 6 or 7, use special biases
        if(band == "6" || band == "7") {
            {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v","bias_max_h","bias_max_v"],band,current_LO);
            //First go to 4mV
            Mixerbias_block_fm(result[2]{0},result[3]{0});
            //Then to 3mV
            Mixerbias_block_fm(result[0]{0},result[1]{0});
        }
        //      
        //Perform diplexer scan at that frequency and M1 setting
        double diplexer_current_min_h = -2.24;
        double diplexer_current_max_h = 2.24;
        double diplexer_current_step = -0.073;
        //i.e. approx 4.48/61
        int n_steps = 61;
        double stepTime = 0.1;
        //
        Scan_diplexer_block_fm(band,diplexer_current_max_h,diplexer_current_max_h,diplexer_current_step,n_steps,stepTime);
        //
        //Check last LO freq done
        if(current_LO == lofreqhigh && endreached == false) {
            endreached = true;
        }
        //Increase LO freq: truncate if step too high
        current_LO = current_LO + lofreqstep;
        if(current_LO > lofreqhigh && endreached == false) {
            current_LO = lofreqhigh;
        }
        //
    }
    //Close-off loop
    //In case of band 6 or 7,go back to nominal values
    if(band == "6" || band == "7") {
        result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,current_LO);
        //First go to 4mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
        //Then to nominal
        result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,current_LO);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
}

//Set DC bias without switching on the chain, block
//All input parameters shall be given by the user
block Conf_diag_LCU_EXPERT_block_fm HIFI 3678 {
}{
    error("Obsolete block. Use Conf_diag_LCU_block_fm HIFI instead");
}

//Generic procedure to send chopper angle using the adequate instrument side
procedure HIFI_CPR_Chopper_Rot_proc_fm {
    double targetAngle = -4.0 in [-8.88,8.5]; // HF_CPR_Chopper_Rot
}{
    //check prime or redundant keyword
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant"],"0",0.0);
    if(result_d[0]{1} == "prime") {
        Hifi_HIFI_P_Chopper_Rot($BBID,targetAngle);
    } else {
        Hifi_HIFI_R_Chopper_Rot($BBID,targetAngle);
    }
}

// BLOCK : Functional Test No 2 (HRS Square M Internal Test)
block HRS_functional_test_No_2_Square_m_block_fm HIFI 3622 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    int repeats = 5;
    //string[] hrsh_blocks_configuration = ["Square_m_ultra","Square_m_wide","Square_m_low","Square_m_nominal","Square_m_high"];
    //Fill in block parameter names for each mode - consequence of SPR-0198
    string[] hrs_blocks_square_m_ultra = ["square_m_ultra","square_m_ultra","square_m_ultra","square_m_ultra","square_m_ultra","square_m_ultra","square_m_ultra","square_m_ultra"];
    string[] hrs_blocks_square_m_wide = ["square_m_wide","square_m_wide","square_m_wide","square_m_wide","square_m_wide","square_m_wide","square_m_wide","square_m_wide"];
    string[] hrs_blocks_square_m_low = ["square_m_hilonom","low","square_m_low","low_nominal","square_m_low_nom","low","square_m_low","high_nominal_low"];
    string[] hrs_blocks_square_m_nom = ["square_m_hilonom","high_nominal","high_nominal","low_nominal","square_m_low_nom","high_nominal","high_nominal","high_nominal_low"];
    string[] hrs_blocks_square_m_high = ["square_m_hilonom","high_nominal","high_nominal","high","high","high_nominal","high_nominal","high_nominal_low"];
    // Configure spectroscopy
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    // Configure LO and attenuators
    //=============================
    HRS_config_att_lo_fm(band,hrs_mode);
    //
    // Loops on the different configurations of the HRS
    //======================================
    //Calls the 5 modes to be checked
    //Square_M_ultra
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_square_m_ultra[0],hrs_blocks_square_m_ultra[1],hrs_blocks_square_m_ultra[2],hrs_blocks_square_m_ultra[3],hrs_blocks_square_m_ultra[4],hrs_blocks_square_m_ultra[5],hrs_blocks_square_m_ultra[6],hrs_blocks_square_m_ultra[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_square_m_ultra[0],hrs_blocks_square_m_ultra[1],hrs_blocks_square_m_ultra[2],hrs_blocks_square_m_ultra[3],hrs_blocks_square_m_ultra[4],hrs_blocks_square_m_ultra[5],hrs_blocks_square_m_ultra[6],hrs_blocks_square_m_ultra[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Square_M_wide
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_square_m_wide[0],hrs_blocks_square_m_wide[1],hrs_blocks_square_m_wide[2],hrs_blocks_square_m_wide[3],hrs_blocks_square_m_wide[4],hrs_blocks_square_m_wide[5],hrs_blocks_square_m_wide[6],hrs_blocks_square_m_wide[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_square_m_wide[0],hrs_blocks_square_m_wide[1],hrs_blocks_square_m_wide[2],hrs_blocks_square_m_wide[3],hrs_blocks_square_m_wide[4],hrs_blocks_square_m_wide[5],hrs_blocks_square_m_wide[6],hrs_blocks_square_m_wide[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Square_M_low
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_square_m_low[0],hrs_blocks_square_m_low[1],hrs_blocks_square_m_low[2],hrs_blocks_square_m_low[3],hrs_blocks_square_m_low[4],hrs_blocks_square_m_low[5],hrs_blocks_square_m_low[6],hrs_blocks_square_m_low[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_square_m_low[0],hrs_blocks_square_m_low[1],hrs_blocks_square_m_low[2],hrs_blocks_square_m_low[3],hrs_blocks_square_m_low[4],hrs_blocks_square_m_low[5],hrs_blocks_square_m_low[6],hrs_blocks_square_m_low[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Square_M_nominal
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_square_m_nom[0],hrs_blocks_square_m_nom[1],hrs_blocks_square_m_nom[2],hrs_blocks_square_m_nom[3],hrs_blocks_square_m_nom[4],hrs_blocks_square_m_nom[5],hrs_blocks_square_m_nom[6],hrs_blocks_square_m_nom[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_square_m_nom[0],hrs_blocks_square_m_nom[1],hrs_blocks_square_m_nom[2],hrs_blocks_square_m_nom[3],hrs_blocks_square_m_nom[4],hrs_blocks_square_m_nom[5],hrs_blocks_square_m_nom[6],hrs_blocks_square_m_nom[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Square_M_high
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_square_m_high[0],hrs_blocks_square_m_high[1],hrs_blocks_square_m_high[2],hrs_blocks_square_m_high[3],hrs_blocks_square_m_high[4],hrs_blocks_square_m_high[5],hrs_blocks_square_m_high[6],hrs_blocks_square_m_high[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_square_m_high[0],hrs_blocks_square_m_high[1],hrs_blocks_square_m_high[2],hrs_blocks_square_m_high[3],hrs_blocks_square_m_high[4],hrs_blocks_square_m_high[5],hrs_blocks_square_m_high[6],hrs_blocks_square_m_high[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //}
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The procedures
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Force boot, procedure: NOT LONGER USED, USE BLOCK INSTEAD
procedure HIFI_force_boot_proc_ops {
    int partition_ID = 0; //0 if forceboot_default. Partition ID in case it should be used. 
}{
    if(partition_ID == 0) {
        mois_comment("ICU booted using default partition.");
        Hifi_HIFI_force_bootdefault();
    } else {
        mois_comment("ICU booted using partition # " + partition_ID);
        Hifi_HIFI_force_bootpartition(partition_ID);
    }
    mois_tmcheck("Verify HIFI HK telemetry packets (3,25,1025) - HIFI_PERIODIC_HK - are arriving every 4 seconds.");
    //mois_tmcheck("Verify that no (5,4) telemetry packet has been received from HIFI.");
    delay(5);
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of OTF observing mode
{int,{int,int,int,int,bool,int,int},double,double} procedure OTFDoubleChopNoRef_post_timing {
    {int,int,int,int,bool,int,int} timing = {21,1780,1,21,false,50,0}; // pre_timing parameter list
    int[] telescopetimes = [300,180,2,2,40,10,20,0];
    int nlines = 1; // Number of rows in the map
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int n_cycles = 1; // Number of map coverages
}{
    // Get all values from the pre_timing section
    int loadlength = timing{0};
    int load_spacing = timing{1};
    int n_loadinterval = timing{2};
    int lineint = timing{3};
    bool end_load_on = timing{4};
    int initlength = timing{5};
    int dangling = timing{6};
    // Get all values from the telescope section
    int telinit = telescopetimes[1];
    // Initial slew time
    int tacc = telescopetimes[2];
    // Acceleration towards line
    int tdec = telescopetimes[3];
    // Deceleration from line
    int tturn = telescopetimes[5];
    // Turn around between lines
    int tline = telescopetimes[4];
    // Time in line
    int trep = telescopetimes[6];
    // Time between two repetitions
    int tend = telescopetimes[7];
    // Final deceleration time
    // Check the length of the telescope slew relative to the integration time
    if(tline < lineint) {
        CError("OTF scan length returned by telescope too short for instrument.");
    }
    // Now we can actually determine n_loadinterval including the overheads
    int lineduration = tline + tturn + imax(trep - tturn,0) / nlines;
    n_loadinterval = load_spacing / lineduration;
    if(n_loadinterval < 1) {
        SError("Scan duration too long for load period. " + "Reduce the number of chop cycles.");
    }
    // Make sure that load slews occur at the same position in each coverage
    int nlines_tot = nlines * n_cycles;
    n_loadinterval = IMultiple(n_loadinterval,nlines);
    // If no load required parameter has to be 0
    if(n_loadinterval > nlines_tot) {
        // Determine need for final load measurement
        double rest = double(nlines_tot % n_loadinterval) + 0.5;
        end_load_on = rest > 0.5001 * double(n_loadinterval);
    } else {
        if(n_loadinterval > nlines) {
            n_loadinterval = nlines;
        }
        // In all these cases a final load will be made anyway in regular pattern
        end_load_on = false;
    }
    // Hold time needed for load
    // To use the state machine we waste the deceleration time 
    // which could be used in principle for the load measurement as well
    int tover = imin(tturn - tdec,trep + tacc);
    int holdlength = imax(loadlength - tover,0);
    // Dangling load measurement
    if(end_load_on) {
        dangling = loadlength;
    } else {
        // whenever a load occurs we also have one at the end
        if(n_loadinterval <= nlines_tot) {
            dangling = loadlength - holdlength;
        }
    }
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    // Compute duration of measurement
    int n_load = nlines_tot / n_loadinterval;
    int maptime = nlines_tot * (tline + tturn) + n_cycles * (trep + tacc + tdec - tturn) + n_load * holdlength;
    // Telescope dead time irelevant for mode without baseline reference
    double tdead = 0.0;
    // Cycle given by switch cycle
    double tscan = 2.0 * double(data_time);
    // The initial time is no longer contained in the total time
    // int totaltime=imax(initlength,telinit);
    int totaltime = maptime + dangling - trep + tend;
    // show gyro-propagation messages
    // no gyro-propagation for line_scan_pointing
    GCPMessages(0,maptime,tend);
    // Return all the times needed in the observing mode modules

    return {totaltime,{loadlength,load_spacing,n_loadinterval,holdlength,end_load_on,initlength,dangling},tscan,tdead};
}

// Set the whole instrument to standby II mode from primary
// This will set the FPU to band 0, backend in standby, and LO in standby
// Will keep HBB, upconverters, chopper on
mode HifiManCmd_HIFI_primary_to_standbyII {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
    string chopper_loop = "OPEN" in ["OPEN","CLOSE"]; //chopper loop status
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    Mode_status_check_primary(laser_H,laser_V,chopper_loop);
    //Standby should always correspond to band0, lofreq=0
    string band = "0";
    double lo_freq = 0.0;
    mois_comment("Set HIFI to standby mode II with " + laser_H + " kept on and chopper loop " + chopper_loop);
    StartMode_block_ops();
    //Needs to duplicate hrs_mode word:
    string[] hrs_mode = ["wb","wb"];
    //LO stand-by.
    mois_step("Set LOU to standby mode");
    mois_comment("Switch off LSU RF");
    LCU_switch_off_block_ops();
    mois_comment("Switch to standby");
    LCU_standby_block_ops();
    //FPU stand-by
    mois_step("Set HIFI FPU to standby mode with internal load heater kept ON");
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    Init_MSA_ops("0",chopper_loop,0.0,result[0]{0},"ON",prime_or_redundant);
    //HRS stand-by
    mois_step("Set HIFI HRS-H and HRS-V spectrometers to standby");
    HRS_standby_block_ops(band,hrs_mode);
    //WBS stand-by
    mois_step("Set HIFI WBS-H and WBS-V spectrometers to standby");
    WBS_standby_block_ops(band,laser_H,laser_V);
    //
    StopMode_block_ops();
    Mode_status_check_standby_II(laser_H,laser_V,chopper_loop,"down",prime_or_redundant);
}

{int,double,double,double,double,double} obs HifiSScanModeFSwitchNoRef {
    string modeName = "fs-freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_cycles = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - Frequency Switch noRef",{data_time,0,0,0,0,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = SScanFSwitchNoRef_pre_timing(band,lo_freq,lo_freq_up,redundancy,freq_throw,effResolution,hr1,hr2,wb1,wb2,data_time,n_cycles,n_freq_point,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,double,double,int} tpar = Fine_telescope(naifid,onPosition,band,reffreq,pre_timing{0});
    // Dummy call to spacecraft command
    int[] telescopetimes = basic_fine_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,bool,int,int},double,double} post_timing = SScanChopNoRef_post_timing(pre_timing{0},telescopetimes);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = Fine_telescope(naifid,onPosition,band,reffreq,post_timing{1});
    // Call telescope command
    telescopetimes = basic_fine_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    // normal pre_timing values
    int loadlength = post_timing{1}{2};
    int n_per_on = post_timing{1}{4};
    int n_load_on = post_timing{1}{5};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        SScanFSwitchNoRef_commanding(band,reffreq,freq_throw,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,n_per_on,n_load_on,groupnumber,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SingleChop_deadtimes("fs",band,reffreq,hr1,hr2,wb1,wb2,data_time,n_per_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanChopNoRef_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,n_per_on * imax(n_load_on,1),true,tscan,tdead);
    // Evaluate performance
    SScanChopNoRef_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_per_on * imax(n_load_on,1),groupnumber * n_freq_point,true,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

////////////////////////////////////
// DBS raster observing mode
// 
// Combination of four modules implementing the new structure 
//
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcDBSRaster {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,100]; // Number of rows in the map
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the raster line
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Mapping - DBS Raster Map slowChop",{data_time,0,0,n_switch_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = DBSRaster_pre_timing(nlines,npoints,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    // Check for NoddingInRaster or NoddingOfRaster
    int scansize = pre_timing{10};
    if(scansize > 1) {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,double,double,int,int,int,int,int} tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        // Dummy call to spacecraft command
        int[] telescopetimes = nodding_of_raster_pointing(false,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double,int,int,int,double,double,int,int,int,int} tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        telescopetimes = nodding_raster_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSRaster_post_timing(pre_timing,telescopetimes,nlines,npoints,n_switch_on,n_cycles,load_interval,false);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    if(scansize > 1) {
        tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        // Call telescope command
        telescopetimes = nodding_of_raster_pointing(true,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        telescopetimes = nodding_raster_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        DBSRaster_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,false);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = DBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints,n_cycles,n_seq * imax(n_load,1),tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

////////////////////////////////////////
// Procedure to calculate the pre timing
//
{int,int,int,int,int,int,int,int,int,bool,int,int,int} procedure DBS_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_chop = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    // Compute parameters for the instrument timing
    int inttime = 2 * n_chop * data_time;
    int readouttime = data_time;
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // For double phases I can use the added jitterdead in both phases for load
    int halfloadlength = (loadlength - jitterdead + 1) / 2;
    // Compare load interval and nodding interval
    // This determines the order of the loops
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    int n_load = inttime / load_spacing;
    if(load_spacing > 2 * inttime) {
        int n_seq = n_chop;
        bool end_load = false;
        int pointing = inttime + jitterdead;
        int shiftlength = 0;
    } else {
        n_seq = n_chop / (n_load + 1);
        if(n_seq < 1) {
            SError("Chop phase length too long relative to load period.");
        }
        end_load = true;
        inttime = 2 * n_seq * (n_load + 1) * data_time;
        pointing = inttime + halfloadlength + n_load * loadlength + jitterdead;
        shiftlength = halfloadlength;
    }
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,false);
    }
    initlength = initlength + loadlength;
    // Compute the overall cycle length
    // First estimate of the load interval
    int n_loadinterval = imax(load_interval / (2 * pointing),1);
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed for telescope call and post_timing processing

    return {inttime,pointing,readouttime,loadlength,jitterdead,load_spacing,n_load,n_loadinterval,n_seq,end_load,shiftlength,initlength,dangling};
}

/////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing for the mode
// 
int procedure Overhead_timing {
    {double,double} onposition = {0.0,0.0}; // Coordinates of the source
    {double,double} offposition = {0.2,0.2}; // Coordinates of the OFF position
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int clustered = 0; // whether observation is part of spatial/frequency cluster
    int data_time = 4 in [0,5]; // data dump interval limited by the data rates
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Interpret data_time=0 as fast-chop
    if(data_time == 0) {
        int load_datatime = GetStdLoadReadout(band,lo_freq);
        CheckDataTaking(backendreadoutparms,load_datatime);
    } else {
        load_datatime = data_time;
        CheckDataTaking(backendreadoutparms,data_time);
    }
    // Compute parameters for the instrument timing
    int pointing = load_datatime;
    // Resulting integer integration time
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms));
    // Duration of initial set up
    if(clustered == 1) {
        int initlength = 0;
    } else {
        initlength = duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
    }
    initlength = initlength + loadlength;

    return initlength;
}

// Spectra obtained with the mixer bias high in the resistive region
block Spectra_resistive_high_fm HIFI 3230 {
    string band = "1a";
    double bias_h = 0.0;
    double bias_v = 0.0;
    int integ_time = 4; //Total integration time in sec.: at least 2sec !  
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    Mixerbias(bias_h,bias_v);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
}

//Load new OBSW , block
block Patch_OBSW_block_ops HIFI 7928 {
}{
    mois_comment("Assign obsid number to procedure execution");
    mois_spacon("In the following command, the second parameter (OBS_ID) shall be replaced by a Formal Parameter value according to the list provided by the instrument ICC.");
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    //  
    mois_step("Copying OBSW to PM-high");
    int hifi_OBS_destination = 0x3ffff;
    // OBS_destination: start of PM high
    int hifi_OBS_copy_length = 0x20000;
    // OBS_copy_length
    Hifi_HIFI_copy_mem_to_high(hifi_OBS_destination,hifi_OBS_copy_length);
    delay(1);
    //
    mois_step("Construct the OBSW patch");
    mois_spacon("Use the OBSM to prepare the HIFI_load_PRAM TC list to build the patched OBSW that is to be loaded");
    //
    mois_step("Upload the OBSW patch to PM-high");
    mois_spacon("Use the OBSM to run the TC list previously prepared to load the patch of the OBSW. Please be aware at the copy should start from address 0x3ffff.");
    //
    mois_step("Verify integrity of copied OBSW");
    //Check PM memory for OBS 5.4: need to put offsets of starting address for PM high
    mois_spacon("In the following command, the three parameters will be replaced by Formal Parameters provided by the instrument ICC.");
    int check_start = 0x5500 + 0x3ffff;
    int check_end = 0x17d0b + 0x3ffff;
    int check_crc = 0x31a0;
    Hifi_HIFI_check_PM_memory(check_start,check_end,check_crc);
    delay(3);
    mois_spacon("Checks TBD");
    //
    mois_step("Copying uploaded OBSW to DM-low");
    hifi_OBS_destination = 0x3ffff;
    // OBS_destination: start of PM high
    hifi_OBS_copy_length = 0x20000;
    // OBS_copy_length
    Hifi_HIFI_copy_mem_to_low(hifi_OBS_destination,hifi_OBS_copy_length);
    delay(1);
    //The new OBSW should be booted
    mois_tmcheck("Check that the new OBSW patch number HI_SW_Patch has been updated");
}

/////////////////////////////////////////////////////////////////
// Auxiliary routine to restrict data_time to match the pointing
// requirements condition: tpos >=10s
{int,int} procedure MatchMinPointing {
    int data_time_guess = 4; // initial guess for data_time
    int data_time_range = 1; // initial guess for range
    int n_switch = 1; // Number of switches with data_time
}{
    // pointing requirements condition: >=10s
    // one second is always added for command jitter
    if(n_switch * data_time_guess < 9) {
        data_time_guess = 8 / n_switch + 1;
        data_time_range = 1;
    }

    return {data_time_guess,data_time_range};
}

//Stopmode
procedure StopMode_TEI {
}{
    {double,string}[] result = ConfigurationReader("name_lastobsid",["last_obsid_current"],"0",0.0);
    //These are ILT-EGSE commands, not ruled by the 2TC/sec.
    //HifiIltEgse_FPU_set_BB_ID(0);
    //HifiIltEgse_PDU_set_OBS_ID(iround(result[0]{0}));
    //delay(1);
    //HifiIltEgse_PDU_set_BB_ID(0);
    //HifiIltEgse_FPU_set_OBS_ID(iround(result[0]{0}));
    //delay(1);
    //SpireIltEgse_QCC_SETBBID(0);
    //SpireIltEgse_QCC_SETOBSID(iround(result[0]{0}));
    //delay(1);
    //HifiIltEgse_GAS_set_OBS_ID(iround(result[0]{0}));
    //HifiIltEgse_GAS_set_BB_ID(0);
    //delay(1);
}

//////////////////////////////////////////////////////////
// Band switch off: this is a switch to band0
////////////////////////////
//  LCU switch-off, block
block LCU_switch_off_block_fm HIFI 3631 {
}{
    //
    //Automatic failure mode clearance.
    //Should take <0.5s so time included in the switch-off delay
    Hifi_HIFI_HL_Normal($BBID);
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_delays",["switch_off_delay"],"0",0.0);
    int switch_off_delay = iround(result[0]{0});
    //
    //Send command: this is the effective switch-off
    Hifi_HIFI_Conf_nom_LCU_ch0($BBID);
    //
    delay(switch_off_delay);
    //
    //Set heater to their stby value: should not depend on band
    HL_heater_proc_fm("1a","stby");
}

//Set LCU5b back to standby status, procedure
procedure LCU5b_standby_proc_fm {
    string band = "5b"; // HIFI band
    double lo_freq = 1200.0 in [1192.0,1242.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

// Procedure to get the general parameters for the telescope command
// for all engineering observations
{int,int} procedure Eng_pre_timing {
}{
    // Init length
    int initlength = duration(HIFIInitObs());
    int hklength = duration(HIFISetHK("fast",true));
    initlength = initlength + hklength;
    // Final length
    int closelength = duration(HIFICloseObs());
    closelength = closelength + hklength;
    // telescope parameters - none needed any more
    // return everything

    return {initlength,closelength};
}

//Generic procedure for total power
//It takes care of the data-rate computation
procedure HIFI_Spectr_total_power_proc_fm {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    int integ_time = 4; //TOTAL integration time
}{
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"tp",integ_time);
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    Hifi_HIFI_Spectr_total_power($BBID);
    Apply_Total_Power_delay(integ_time,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// Integrate with IF1 off, block
// We take 1 spectrum per phase.
block Stability_noIF1_fm HIFI 3429 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integrations
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    Start_block();
    //The system as is should be ready
    //No use of FPU capabilities.
    //
    //Do a long integration: 4 sec is OK
    //We implement a special spectroscopy configuration with fixed values
    Total_power_spectro_for_Stability_proc_fm(band,n,integ_time,backend,hrs_mode);
}

////////////////////////////////////////
// Standing wave analysis, procedure   NDW
// This is like a radiometry: 4 spectra
//  noretune version
procedure Standing_wave_noretune_fm_COP {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    double[] lo_freq_input = [500.0,500.15,0.02]; //Start, end and step lo_freq for the LO scan
    string los_code = "sc" in ["sc","sh","ss"]; //The line-of-sight code: sc (sky-CBB), sh (sky-HBB), ss (sky-sky)
}{
    // Initial LO tuning at centre frequency of scan
    //
    double lo_freq_ref = (lo_freq_input[0] + lo_freq_input[1]) / 2.0;
    message("LO freq: " + lo_freq_ref);
    if(los_code == "sh") {
        Init_MSA_HBB_fm(band,"CLOSE",lo_freq_ref,"ON");
    } else {
        Init_MSA_CBB_fm(band,"CLOSE",lo_freq_ref,"ON");
    }
    LO_tuning_block_fm(band,lo_freq_ref);
    double lo_freq = lo_freq_input[0];
    //
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_stndwave_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_tune_block_fm(band);
    }
    //
    //Loop on LO frequencies. It is assumed that the LO is tuned at the middle frequency of the scan
    //
    int nbstep = 0;
    //For freq above 1THz rounding makes miss the last step.
    double margin = 0.1 / 1.0E9;
    //0.1Hz
    while(lo_freq <= lo_freq_input[1] + margin) {
        //Set synthesizer to new LO freq.
        LCU_config_nominal_noretune_block_fm(band,lo_freq,lo_freq_ref);
        //
        if(los_code == "sc") {
            //Pair towards sky-CBB
            Sky_Cold_fm_COP(band,integ_time,hrs_mode,backend);
        }
        if(los_code == "sh") {
            //Pair towards sky-HBB
            Sky_Hot_fm_COP(band,integ_time,hrs_mode,backend);
        }
        if(los_code == "ss") {
            //Pair towards sky-sky
            Sky_Sky_fm_COP(band,integ_time,hrs_mode,backend);
        }
        //Increase lo_freq
        lo_freq = lo_freq + lo_freq_input[2];
        nbstep = nbstep + 1;
        //debug_print(lo_freq);
    }
    message("Nb of steps: " + nbstep);
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of OTF observing mode
{int,int,int,int,int,int,int,int} procedure OTFFSwitch_pre_timing {
    int nlines_tot = 1; // Number of rows in the map
    int npoints = 10; // Number of data dumps per row
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq + min(freq_throw,0.0),lo_freq + max(freq_throw,0.0));
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    CheckFswOutOfBand(band,lo_freq,freq_throw,backendreadoutparms);
    // Is the map size an integer multiple of the scan size?
    CheckReasonableLineNumber(nlines_tot,true);
    if(nlines_tot == 1) {
        int n_scans = 1;
    } else {
        if(nlines_tot % n_linesperscan != 0) {
            SError("Map size is no integer multiple of the scan size.");
        }
        n_scans = nlines_tot / n_linesperscan;
    }
    // Compute parameters for the instrument timing
    int n_pp = 2 * npoints * n_switch_on;
    // compute load integration time
    int loadlength = duration(DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Compute parameters for the pointing command
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    int off_inttime = 2 * data_time_off * n_switch_off;
    // OFF integration time
    int off_pointing = off_inttime + jitterdead;
    // increase by commanding jitter
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFIFsw(band,lo_freq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,true);
    }
    initlength = initlength + loadlength;
    // First estimate of the load interval
    int scan_time = n_linesperscan * n_pp * data_time + off_pointing;
    if(scan_time > load_interval) {
        IError("Scan duration too long for required load period. " + "Reduce the map size or increase the step size.");
    }
    int n_loadinterval = imax(load_interval / scan_time,1);
    n_loadinterval = imin(n_loadinterval,32);
    // Make sure that load slews occur at the same position in each coverage
    n_loadinterval = IMultiple(n_loadinterval,n_scans);
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed in the observing mode modules

    return {n_pp,n_scans,off_inttime,off_pointing,loadlength,n_loadinterval,initlength,dangling};
}

// SCR-1243: 14.4 and 14.42 are prohibited LO - shift it to 14.38 and 14.44 GHz
double procedure Check_HRS_prohibited_LO_proc_fm {
    double flo = 15.0; // Input HRS internal LO freq. in GHz
}{
    double checked_flo = flo;
    if(checked_flo == 14.4) {
        checked_flo = flo - 0.02;
    }
    if(checked_flo == 14.42) {
        checked_flo = flo + 0.02;
    }

    return checked_flo;
}

// Automatic magnet tuning, block
// Also assumes backends are ready
// This mode allows some investigation on the input parameters
block Magnet_tuning_expert_block_fm HIFI 3619 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b"]; // HIFI band
    double lo_freq = 522.0; //LO frequency
    string backend_code = "HRS" in ["WBS","HRS"]; //The backend to be used for tuning
    int tune_target_magnet = 40 in [10,85]; //Target WBS illumination percentage during magnet tuning
    double[] input_params = [1.8,7.0,8.0,20.0,10.0,1.0]; //input parameters for expert mode
}{
    Start_block();
    //Set mixer bias to special bias for tuning
    {double,string}[] result = ConfigurationReader("name_confilmix",["bias4magn_h","bias4magn_v","norm_bias_h","norm_bias_v"],band,lo_freq);
    //For bands 1,2 and 5, we must substract 0.09mV to this value
    double bias4magnh = result[0]{0};
    double bias4magnv = result[1]{0};
    if(band == "1a" || band == "1b" || band == "2a" || band == "2b" || band == "5a" || band == "5b") {
        bias4magnh = bias4magnh - 0.09;
        bias4magnv = bias4magnv - 0.09;
    }
    Mixerbias(bias4magnh,bias4magnv);
    double normal_bias_h = result[2]{0};
    double normal_bias_v = result[3]{0};
    //
    //First set magnets to maximum because of hysteresis
    result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
    double magnetcurrentmax_H = result[0]{0};
    double magnetcurrentmax_V = result[1]{0};
    Set_Magnet_current_proc_fm(magnetcurrentmax_H,magnetcurrentmax_V);
    //
    //For band5, wait another 5 sec here
    if(band == "5a" || band == "5b") {
        delay(5);
    }
    //Fetch magnet tuning parameters
    result = ConfigurationReader("name_configmagtune",["nMagnet","stepT","mx_mg_span"],band,lo_freq);
    //
    //Tuning strategy: scan nMagnet points over -10% to +10% of nominal value
    //at the frequency of interest
    int nMagnet = iround(input_params[4]);
    double stepT = input_params[5];
    double h_mx_mg0 = input_params[1];
    double v_mx_mg0 = input_params[2];
    double scan_range = input_params[3] / 100.0 * max(h_mx_mg0,v_mx_mg0);
    double mx_mg_step = -1.0 * scan_range / double(nMagnet);
    //Starting scan values
    h_mx_mg0 = h_mx_mg0 - mx_mg_step * double(nMagnet) / 2.0;
    v_mx_mg0 = v_mx_mg0 - mx_mg_step * double(nMagnet) / 2.0;
    //
    //Set magnets to starting value to do backend tuning
    Set_Magnet_current_proc_fm(h_mx_mg0,v_mx_mg0);
    //
    //Tune attenuators of backends before magnet tuning
    ///The following is not yet done. Still take as input parameter
    //result = ConfigurationReader("name_configwbs",["tune_target_magnet"],band,lo_freq);
    //int tune_target_magnet = iround(result[0]{0});
    //
    //Perform tuning: check which backend shall be used
    int magtune_delay = 0;
    if(backend_code == "WBS") {
        Hifi_HIFI_Tune_WBS($BBID,tune_target_magnet);
        //Get delay
        result = ConfigurationReader("name_delays",["wbs_tune_delay"],band,0.0);
        delay(iround(result[0]{0}));
        //
        Hifi_HIFI_Tune_mxmgc_useWBS($BBID,stepT,nMagnet,h_mx_mg0,v_mx_mg0,mx_mg_step);
        //Compute delay
        magtune_delay = iceil(1.0 + 0.94 + double(nMagnet) * (stepT + 1.05)) + 1;
        //according to OBS 4.4: extra second added
    } else {
        Hifi_HIFI_Tune_HRS($BBID);
        //Get delay
        result = ConfigurationReader("name_delays",["hrs_tune_delay"],band,0.0);
        delay(iround(result[0]{0}));
        //
        Hifi_HIFI_Tune_mxmgc_useHRS($BBID,stepT,nMagnet,h_mx_mg0,v_mx_mg0,mx_mg_step);
        magtune_delay = iceil(1.0 + 0.072 + double(nMagnet) * (stepT + 0.132)) + 1;
        //according to OBS 4.4: extra second added
    }
    //
    delay(magtune_delay);
    //debug_print(magtune_delay);
    //Set mixer bias back to nominal value at frequency of interest
    Mixerbias(normal_bias_h,normal_bias_v);
    //
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double} procedure DBS_deadtimes {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval
    int n_chop = 3; // number of chop cycles in one integration
    int n_load = 0; // number of integrations in one pointing phase -1
    double tdead = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Compute parameters for the instrument timing
    {double,double} tinst = GetInstDeadSlowChop(data_time,2 * n_chop,"chop",band,lo_freq,backendreadoutparms);
    // dead time
    double tdeadint = double(data_time * 2 * n_chop) - tinst{0};
    // subtract dead times in switches
    // keep dead times between A-A and B-B in total dead time
    tdeadint = tdeadint - double(n_chop) * tinst{1};
    // Total dead time per cycle
    double tdead_tot = tdead + double(2 * (n_load + 1)) * tdeadint;
    // Integration time
    double tphaseint = tinst{0} / double(2 * n_chop);

    return {tdead_tot,tphaseint,tinst{1}};
}

// Radiometric noise from a symmetric two-phase observation
// This is still to be scaled by a factor 1.0/(B_fluct*T_Allan)
double procedure TwoPhaseRadioNoise {
    double x = 0.1; // value for integration time relative to Allan time
}{
    double y = AsymmetricRadioNoise(x,x,1.0);

    return y;
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CUS scripts for Manual Procedures MOC
//
// DT - 27-Feb-06
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The modes
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Write in EEPROM
mode HifiManCmd_write_eeprom {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    Mode_status_check_intermediate();
    StartMode_block_ops();
    mois_comment("EEPROM writing of latest uploaded OBSW");
    mois_spacon("This procedure should be executed immediately after any of the OBSM procedures, on the condition that the corresponding uploaded OBSW version needs to be written on the EEPROM. Please check procedure SRON_U/HIFI/PR/2007-007 for background and details applicable to the OBSW version of interest.");
    Write_EEPROM_block_ops();
    StopMode_block_ops();
}

//Set LOU to nominal, procedure
//Set LOU in nominal mode with no
//channel selected
procedure Set_LO_Nominal_proc_fm {
}{
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_delays",["set_to_nominal_delay"],"0",0.0);
    int set_to_nominal_delay = iround(result[0]{0});
    //
    Hifi_HIFI_HL_Normal($BBID);
    delay(set_to_nominal_delay);
    //
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CUS scripts for LOU and LCU operations.
//
// DT - 17-Feb-06
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The modes
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// See fm_testmodes.cus
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The procedures
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Block to activate FSW1/FSW2 register
block Activate_FSW_register_block_fm HIFI 3955 {
    string register = "FSW1" in ["FSW1","FSW2"]; //Register to activate: FSW1 or FSW2
}{
    if(register == "FSW1") {
        Hifi_HIFI_HL_set_FSW1($BBID);
    } else {
        Hifi_HIFI_HL_set_FSW2($BBID);
    }
}

////////////////////////////////////////
// Standing wave analysis, procedure   NDW
// This is like a radiometry: 4 spectra
// retune version
procedure Standing_wave_retune_fm {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    double[] lo_freq_input = [500.0,500.15,0.02]; //Start, end and step lo_freq for the LO scan
    int nb_retune = 5; //frequency at which we retune
}{
    // Initial LO tuning at centre frequency of scan  (NDW)
    // Not applicable here
    double lo_freq_ref = (lo_freq_input[0] + lo_freq_input[1]) / 2.0;
    //LO_tuning_block_fm(band, lo_freq_ref); 
    double lo_freq = lo_freq_input[0];
    //
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_stndwave_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration
    //Slowchop will be used for all bands - FSW no longer considered for HEBs
    //
    int[] res = [0,0];
    int total_time = 0;
    res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    total_time = res[0] * res[1];
    //
    //Loop on LO frequencies. It is assumed that the LO is tuned at the middle frequency of the scan
    //
    int retune = 0;
    while(lo_freq <= lo_freq_input[1]) {
        //
        //We will retune at the running frequency every 5 settings (starting with the first)
        retune = iround((lo_freq - lo_freq_input[0]) / lo_freq_input[2]) % nb_retune;
        if(retune == 0) {
            LO_tuning_block_fm(band,lo_freq);
        } else {
            //Set synthesizer to new LO freq.
            LCU_config_nominal_noretune_block_fm(band,lo_freq,lo_freq_ref);
            // NDW
        }
        //
        //First internal loads
        Hot_cold(band,hrs_mode,backend,res[0] * res[1],"slowchop",0,0);
        //Then external loads - this will drop if not ILT-context
        //Hot_cold_external(band,res[0]*res[1],backend);
        //Increase lo_freq
        lo_freq = lo_freq + lo_freq_input[2];
    }
}

// Vector scan calibration for a given LO band
// Ues domains of frequencies to be scanned for each LO sub-band
procedure Vecscan_calibration_proc_fm_TV {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //  
    LCU_switchon_proc_fm(band);
    //Wait an extra delay of 1 min for short term stabilization
    delay(60);
    //
    //Get the list of frequencies to be used for the scan
    string tab = "config_vecscan_TV.config";
    double bandnb = GetBandCode(band);
    double lofreqlow = dlookup(tab,"" + iceil(bandnb),"lofreqlow");
    double lofreqhigh = dlookup(tab,"" + iceil(bandnb),"lofreqhigh");
    double lofreqstep = dlookup(tab,"" + iceil(bandnb),"lofreqstep");
    //
    double current_LO = lofreqlow;
    bool endreached = false;
    //Loop on key frequencies per LO band
    while(current_LO <= lofreqhigh && endreached == false) {
        //Configure FPU at that frequency
        Init_MSA_fm(band,"CLOSE",current_LO,"ON");
        //
        //Perform vector scan within BLUE limits at that frequency
        Vector_scan_BLUE_LIMIT_block_fm(band,current_LO);
        //LCU_CLEAR_ERROR_block_fm();
        //
        //Check last LO freq done
        if(current_LO == lofreqhigh && endreached == false) {
            endreached = true;
        }
        //Increase LO freq: truncate if step too high
        current_LO = current_LO + lofreqstep;
        if(current_LO > lofreqhigh && endreached == false) {
            current_LO = lofreqhigh;
        }
    }
    //
}

// Initialisation of FPU, block with both MSA in use
// It is for warm context, except FIF1 which is cold context
block Init_MSA_fm_warm_FIF1cold HIFI 3219 {
    string band = "1a"; // HIFI band
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReaderWarm("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    //
    //Get FIF1-H for cold context
    result_d = ConfigurationReader("name_confilfpu",["fif1v_h","fif1c_h"],band,lo_freq);
    volt_H_FIF_1 = result_d[0]{0};
    curr_H_FIF_1 = result_d[1]{0};
    //
    // 
    result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    //Get FIF1-V for cold context
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v"],band,lo_freq);
    volt_V_FIF_1 = result_d[0]{0};
    curr_V_FIF_1 = result_d[1]{0};
    //
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReaderWarm("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    //Get biases
    result_d = ConfigurationReaderWarm("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReaderWarm("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReaderWarm("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReaderWarm("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReaderWarm("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //In case of band 6 or 7, bias have been set to 4mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReaderWarm("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    //Magnet are so far at maximum value. Now set to nominal
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReaderWarm("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
        Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
        delay(1);
    }
    //
    Hifi_HIFI_non_periodic_hk_FCU();
}

// Recalculate and verify LCU memory checksum
block LcuChecksumRecalc_ops HIFI 7904 {
    string section = "P" in ["P","R"];
}{
    int expected_sum = ilookup("LcuChecksumTable.config",section,"normal");
    // initial install of default safe table - simulate transition to normal
    Hifi_HIFI_LCU_Single($BBID,"HL_DEF_SAFE");
    delay(1);
    //Stop LCU HK collection - see SPR-1679
    //Get applicable HK rate
    mois_comment("Stop LCU HK collection");
    {double,string}[] result_d = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    string hk_rate = result_d[0]{1};
    Hifi_HIFI_Housekeeping_on(hk_rate,"ON","OFF","ON","ON","ON","ON");
    delay(1);
    //
    mois_spacon("In the following TC, the third parameter (HP233197) should be treated as FP.");
    Hifi_HIFI_check_LCU_memory($BBID,3000,expected_sum);
    //add 2sec to the initial 4sec - SPR-1744
    delay(6);
    //Restore HK
    mois_comment("Resume LCU HK collection");
    Hifi_HIFI_Housekeeping_on(hk_rate,"ON","ON","ON","ON","ON","ON");
    delay(1);
    //
    mois_tmcheck("Check with HIFI representative that parameter HM245194 has taken the expected checksum value. Also HM247194 should be set to OK");
    mois_comment("If the above is not true, the upload has failed and the HIFI ICU needs to be reset. For this, please use the corresponding OBCP.");
}

// Total noise from an OTF line for the special case of a
// multiple scan of the same line
// Normalized to mapping without overhead
// 
double procedure OtfRepeatedNoise {
    double num_scans = 2.0; // number of scans of the same line
    double n = 10.0; // number of points in one scan
    double[] parameters = [0.02,0.4,0.05,0.667,2.5]; // Parameters: integration time, delay, slew from OFF relative to Allan time, ratio of t_off time to sqrt(n)*t_on, drift exponent
}{
    // Assign parameters
    double x = parameters[0];
    double d = parameters[1];
    double doff = parameters[2];
    double qval = parameters[3];
    double alpha = parameters[4];
    // Make corrections for different calibration
    double qcorr = qval * sqrt(num_scans);
    {double,double} noisevalues = OtfNoiseValues(num_scans * n,[x,d,doff,qcorr,alpha]);
    // The radiometric noise here is only accurate for nscans=1,2.
    // For other lengths we make a small error.
    double yn = noisevalues{0};
    yn = yn / num_scans;
    // The drift noise might also be reduced somewhat due to adding up
    // different scans. The effect is basically unknown and ignored here.
    double yd = noisevalues{1};
    double y = yn + yd;

    return y;
}

//HIFI LO tuning only for M1/M2 investigation in 3b, block
//Target current is read from look-up table
block LCU_config_w_M1M2M3_block_fm HIFI 3923 {
    string band = "3b" in ["3b","3b"]; // HIFI band
    double lo_freq = 930.0; //LO frequency
    double m1 = 10.0; //M1 multiplier voltage
    double m2 = -8.0; //M2 multiplier voltage
    double m3 = 1.5; //M3 multiplier voltage
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    string mixer_polarization = result[0]{1};
    //
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = m1;
    //result[1]{0};
    double m2_v = m2;
    //result[2]{0};
    double m3_v = m3;
    //result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    double drain2_v_start = drain2_bluemax;
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    if(band == "3b") {
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum);
        //Send command: specific to M3 in 3b
        delay(config_lo_delay);
        //
        //Additional read of TM pages
        LCU_Read_TM_pages_proc_fm();
    }
    //
}

////////////////////////////////////
// Load chop observing mode
// 
// The implementation now assumes that the corresponding Herschel
// pseudo-pointing mode will be available
//
{int,double,double,double,double,double} obs HifiPointProcLoadChop {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    bool refSelected = true; // Dummy parameter required by HSPOT
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half load-sky-sky-load cycles on ON
    int n_switch_off = 2 in [1,900]; // number of half load-sky-sky-load cycles on OFF
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF calibration cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Single Point - Load Chop Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,0,0,0,n_cycles,load_interval});
    // position switch
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} pre_timing_ps = LoadChop_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_cycles,load_interval,docommands);
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar_ps = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,pre_timing_ps,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar_ps{0},tpar_ps{1},tpar_ps{2},tpar_ps{3},tpar_ps{4},tpar_ps{5},tpar_ps{6},tpar_ps{7},tpar_ps{8},tpar_ps{9},tpar_ps{10},tpar_ps{11},tpar_ps{12},tpar_ps{13},tpar_ps{14},tpar_ps{15},tpar_ps{16},tpar_ps{17},tpar_ps{18},true);
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},int,bool,double,double} post_timing_ps = DoubleChop_post_timing(pre_timing_ps,telescopetimes,n_cycles);
    // Now the actual observation starts
    // Prepare telescope command
    tpar_ps = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,post_timing_ps{1},n_cycles);
    // Call telescope command 
    telescopetimes = nodding_pointing(true,tpar_ps{0},tpar_ps{1},tpar_ps{2},tpar_ps{3},tpar_ps{4},tpar_ps{5},tpar_ps{6},tpar_ps{7},tpar_ps{8},tpar_ps{9},tpar_ps{10},tpar_ps{11},tpar_ps{12},tpar_ps{13},tpar_ps{14},tpar_ps{15},tpar_ps{16},tpar_ps{17},tpar_ps{18},true);
    // Consistency check
    int totaltime = post_timing_ps{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    //////////////////////////////////////////////////////////////////////
    int on_inttime = post_timing_ps{1}{0};
    int off_inttime = post_timing_ps{1}{1};
    int on_pointing = post_timing_ps{1}{2};
    int off_pointing = post_timing_ps{1}{3};
    int loadlength = post_timing_ps{1}{4};
    int n_loadinterval = post_timing_ps{1}{7};
    int n_per_on = post_timing_ps{1}{8};
    int n_per_off = post_timing_ps{1}{9};
    int n_load_on = post_timing_ps{1}{10};
    int n_load_off = post_timing_ps{1}{11};
    bool end_load_on = post_timing_ps{1}{12};
    bool end_load_off = post_timing_ps{1}{13};
    int initshiftlength = post_timing_ps{2};
    bool final_load = post_timing_ps{3};
    double tscan = post_timing_ps{4};
    double tdead = post_timing_ps{5};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    //////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        LoadChop_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_per_on,n_per_off,n_loadinterval,n_load_on,n_load_off,end_load_on,end_load_off,final_load,startobs,telescopetimes,loadlength,initshiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = DoubleChop_deadtimes("lchop",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_per_on,n_per_off,n_load_on,n_load_off,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = LoadChop_noisecomputer(band,lo_freq,effResolution,oneGHzReference,on_inttime,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    DoubleChop_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,n_per_on * (n_load_on + 1),n_per_off * (n_load_off + 1),false,tscan,on_pointing,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Tune for frequency switch
procedure TuneHIFIFsw {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {bool,int,double[],bool[]} hrs1parms = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets,subbands used}
    {bool,int,double[],bool[]} hrs2parms = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets,subbands used}
    bool wbs1parms = true; // WBS1 parameter =used
    bool wbs2parms = true; // WBS2 parameter =used
    string level = "normal"; // Name of target level
}{
    // Check for allowed configuration
    double maxstep = GetMaxFreqThrow(band,lo_freq);
    if(abs(freq_throw) > maxstep) {
        int show_lo = ifloor(lo_freq / 1000.0);
        IError("Frequency throw too large. Maximum throw allowed at " + show_lo + "GHz: " + maxstep + "MHz.");
    }
    // Switch to high HK rate
    HIFISetHK("fast",true);
    ConfigureFPU(band,lo_freq + freq_throw / 2.0,true);
    ConfigureBackend(band,lo_freq + freq_throw / 2.0,hrs1parms,hrs2parms);
    HIFITuneFsw(band,lo_freq,lo_freq + freq_throw,hrs1parms{0},hrs2parms{0},wbs1parms,wbs2parms,level);
    // Switch to standard HK rate
    HIFISetHK("normal",true);
}

//Stopmode
procedure StopMode {
}{
    {double,string}[] result = ConfigurationReader("name_lastobsid",["last_obsid_current"],"0",0.0);
    //These are ILT-EGSE commands, not ruled by the 2TC/sec.
    //HifiIltEgse_FPU_set_BB_ID(0);
    //HifiIltEgse_FPU_set_OBS_ID(iround(result[0]{0}));
    //delay(1);
    //SpireIltEgse_QCC_SETBBID(0);
    //SpireIltEgse_QCC_SETOBSID(iround(result[0]{0}));
    //delay(1);
    //HifiIltEgse_PDU_set_BB_ID(0);
    //HifiIltEgse_PDU_set_OBS_ID(iround(result[0]{0}));
    //delay(1);
    Hifi_HIFI_Set_OBS_ID(0,iround(result[0]{0}));
    delay(1);
}

///////////////////////////////////////////////////////////////////
// Procedure to compute detailed post timing for the version of the
// load chop mode without baseline measurement
// 
{int,{int,int,int,int,int,int,bool,int,int},double,double} procedure SingleChopNoRef_post_timing {
    {int,int,int,int,int,int,bool,int,int} pre_timing = {16,16,21,1800,2,0,false,50,0}; // pre_timing parameter list
    int[] telescopetimes = [300,180,0];
}{
    // Get all values from the pre_timing section
    int on_inttime = pre_timing{0};
    int on_pointing = pre_timing{1};
    int loadlength = pre_timing{2};
    int load_spacing = pre_timing{3};
    int n_per_on = pre_timing{4};
    int n_load_on = pre_timing{5};
    bool end_load_on = pre_timing{6};
    int initlength = pre_timing{7};
    int dangling = pre_timing{8};
    // Get all values from the telescope section
    int tend = telescopetimes[2];
    // Final deceleration time
    // No further computations needed
    int looplength = on_pointing;
    double tscan = double(on_inttime) / double(n_per_on * (n_load_on + 1));
    // No telescope dead time in fine pointing
    double tdead = 0.0;
    // dangling load time
    if(end_load_on) {
        dangling = loadlength;
    }
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    // Compute total duration
    // The initial time is no longer contained in the total time  
    // int totaltime=imax(initlength,telinit);
    int totaltime = looplength + dangling + tend;
    // show gyro-propagation messages
    // no gyro-propagation for fine_pointing
    GCPMessages(0,on_pointing,tend);
    // Return all the times needed in the telescope and instrument modules

    return {totaltime,{on_inttime,on_pointing,loadlength,load_spacing,n_per_on,n_load_on,end_load_on,initlength,dangling},tscan,tdead};
}

// Set magnet currents for both polarizations, block
block Set_Magnet_current_block_fm HIFI 3644 {
    double mag_curr_h = 1.0; //Magnet current H polarization
    double mag_curr_v = 1.0; //Magnet current V polarization
}{
    //Start_block();
    Hifi_HIFI_CH1_MX_MG_C($BBID,mag_curr_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,mag_curr_v);
    delay(1);
}

//HIFI-COP-7.2-FT: Regular FT during PV and routine for health monitoring
procedure HealthMon_FT_COP_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Chopper health check: needs to start in open loop
    Chopper_FT1_COP_proc_ops(prime_or_redundant);
    Chopper_FT2_COP_proc_ops(prime_or_redundant);
    Chopper_FT3_COP_proc_ops(prime_or_redundant);
    //At that stage the loop is closed again
    //
    WBS_FT_COP_proc_ops(prime_or_redundant);
    HRS_FT_COP_proc_ops(prime_or_redundant);
    //
    string[] band = ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"];
    //
    //Reduced version of FP and LO FT: only IVC
    for(int i = 0 .. 13) {
        if(i % 2 == 0) {
            double[] cresult_d = CalibrationReader("name_keyfreq",["keyfreq"],band[i],0.0);
            FPU_FT_IVC_COP_proc_ops(band[i],prime_or_redundant);
        }
        LO_FT_IVC_COP_proc_ops(band[i],prime_or_redundant);
    }
    //Chopper response time
    Chopper_Response_time_COP_proc_ops(prime_or_redundant);
    //Diplexer response time
    string[] band_dip = ["3a","4a","6a","7a"];
    for(int j = 0 .. 3) {
        Diplexer_Response_time_COP_proc_ops(band_dip[j],"H");
        Diplexer_Response_time_COP_proc_ops(band_dip[j],"V");
    }
    //
}

////////////////////////////////////
//Special blocks taken from MOC_CUS
////////////////////////////////////
//Chopper rotation block. It takes into account
//overshoot risk and performs the rotation in
//2 steps if the targetted positions are either of the end stops
block Chopper_Rotation_block_fm_COP HIFI 3746 {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string chop_current_position = "chop_hot_ang"; //Current chopper position
    string chop_target_position = "chop_cold_ang"; //Targetted chopper position
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Start_block(); 
    //Retrieve angles of corresponding positions
    {double,string}[] result_d = ConfigurationReader("name_chopper",[chop_current_position,chop_target_position,"chop_endstopright_ang","chop_endstopleft_ang","overshoot"],band,0.0);
    double chop_current_angle = result_d[0]{0};
    double chop_target_angle = result_d[1]{0};
    double chop_endstopright_angle = result_d[2]{0};
    double chop_endstopleft_angle = result_d[3]{0};
    double overshoot = result_d[4]{0};
    string chop_target_name = result_d[1]{1};
    string chop_current_name = result_d[0]{1};
    int step = 1;
    //
    //Check whether the rotation may reach either of the end stops, i.e.
    //go beyond either the HBB or M3_left
    ///// We suppose here overshoot to be 0, so the 2 steps only occur when targetting
    ///// the end stops strictly.
    overshoot = 0.0;
    double total_angle = abs(chop_target_angle - chop_current_angle) * (1.0 + overshoot);
    //
    //The endstop that one may hit depends on the rotating direction
    //Case were endstop is the left one
    double angle_to_endstop = abs(chop_endstopleft_angle - chop_current_angle);
    if(chop_target_angle > chop_current_angle) {
        //then end stop is the right one
        angle_to_endstop = abs(chop_endstopright_angle - chop_current_angle);
    }
    //debug_print(total_angle);
    //debug_print(angle_to_endstop);
    if(total_angle >= angle_to_endstop) {
        message("Chopper expected to hit the endstop. Rotation done in two steps");
        step = 2;
    }
    //If we have two steps necessary, the middle position between current and
    //targetted position is used.
    result_d = ConfigurationReader("name_confilfpu",[chop_target_name,chop_current_name],band,0.0);
    double chop = result_d[0]{0};
    double chop_intermediate = (result_d[0]{0} + result_d[1]{0}) / 2.0;
    //
    chop = Check_Chopper_Prime_Redundant_COP(chop,prime_or_redundant);
    if(step == 1) {
        if(prime_or_redundant == "Prime") {
            Hifi_HIFI_P_Chopper_Rot($BBID,chop);
        } else {
            Hifi_HIFI_R_Chopper_Rot($BBID,chop);
        }
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent voltage
        delay(1);
    }
    if(step == 2) {
        chop_intermediate = Check_Chopper_Prime_Redundant_COP(chop_intermediate,prime_or_redundant);
        if(prime_or_redundant == "Prime") {
            Hifi_HIFI_P_Chopper_Rot($BBID,chop_intermediate);
        } else {
            Hifi_HIFI_R_Chopper_Rot($BBID,chop_intermediate);
        }
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent voltage
        delay(1);
        if(prime_or_redundant == "Prime") {
            Hifi_HIFI_P_Chopper_Rot($BBID,chop);
        } else {
            Hifi_HIFI_R_Chopper_Rot($BBID,chop);
        }
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent voltage
        delay(1);
    }
}

{string,double,double}[] procedure HifiPointModePositionSwitchSequencerInit {
    string modeName = "pos";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,5]; // data dump interval limited by the data rates
    int n_int_on = 3 in [2,1800]; // number of data dumps for integration per phase
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // Compute derived quantities
    int int_time_guess = imax(iceil(0.3 * allan_time_lores),datalimit);
    int data_time_guess = imin(5,int_time_guess);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_int_on_guess = imax(int_time_guess / data_time_guess,2);
    int n_int_on_range = 2 - n_int_on_guess;
    if(n_int_on_range == 0) {
        n_int_on_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,n_int_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    // Contruct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_int_on",double(n_int_on_guess),double(n_int_on_range)}];

    return retvalues;
}

// Stability test, procedure, double-beam-switch chop
// Differential stability between M3left and M3right. 
procedure Proc_stability_dbs {
    string band = "1a"; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total (co-added) integration time of a phase in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string shutter = "open" in ["open","closed"]; // Shutter position during measurement
    string chopmode = "slowchop" in ["slowchop","fastchop"]; //Whether to use slowchop or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    //
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //Look at HBB for att. tuning
    //Shutter_rotate_proc_fm(shutter);
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        //Configure and tune backends
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration after tuning: done later
    //Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    Stability_dbs_fm(band,n,integ_time,hrs_mode,backend,chopmode,chop_phase);
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
    //2 sec. integration
}

// Initialisation of FPU, block with both MSA in use
// Looks at the hot load !
// It is for cold context !
block Init_MSA_CBB_fm HIFI 3998 {
    string band = "1a"; // HIFI band
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
    string hbb_heater = "ON" in ["ON","OFF"]; //hot source on/off
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    if(hbb_heater == "ON") {
        result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,lo_freq);
        calibcurrent = result_d[0]{0};
    }
    //
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_confilfpu",["chop_cold"],band,0.0);
    //result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],
    // 						     band,0.0);  
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //In case of band 6 or 7, bias have been set to 4mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    //Magnet are so far at maximum value. Now set to nominal
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
        Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
        delay(1);
    }
    //
    //Hifi_HIFI_non_periodic_hk_FCU ();
}

// Automatic magnet tuning, block
// Also assumes backends are ready
// This is to be used in cold context
block Magnet_tuning_block_aot HIFI 6609 {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b"]; // HIFI band
    double lo_freq = 978.2; //LO frequency
    string backend_code = "HRS" in ["WBS","HRS"]; //The backend to be used for tuning
}{
    //Set mixer bias to special bias for tuning
    {double,string}[] result = ConfigurationReader("name_confilmix",["bias4magn_h","bias4magn_v","norm_bias_h","norm_bias_v"],band,lo_freq);
    //For bands 1,2 and 5, we must substract 0.09mV to this value
    double bias4magnh = result[0]{0};
    double bias4magnv = result[1]{0};
    if(band == "1a" || band == "1b" || band == "2a" || band == "2b" || band == "5a" || band == "5b") {
        bias4magnh = bias4magnh - 0.09;
        bias4magnv = bias4magnv - 0.09;
    }
    Mixerbias(bias4magnh,bias4magnv);
    double normal_bias_h = result[2]{0};
    double normal_bias_v = result[3]{0};
    //
    //First set magnets to maximum because of hysteresis
    result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
    double magnetcurrentmax_H = result[0]{0};
    double magnetcurrentmax_V = result[1]{0};
    Set_Magnet_current_proc_fm(magnetcurrentmax_H,magnetcurrentmax_V);
    //For band5, wait another 5 sec here
    if(band == "5a" || band == "5b") {
        delay(5);
    }
    //
    //Fetch magnet tuning parameters
    //Middle of the scan
    result = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
    double h_mx_mg0 = result[0]{0};
    double v_mx_mg0 = result[1]{0};
    //
    result = ConfigurationReader("name_configmagtune",["nMagnet","stepT","mx_mg_span"],band,lo_freq);
    //
    //Tuning strategy: scan nMagnet points over -span/2 to +span/2% of nominal value
    //at the frequency of interest
    int nMagnet = iround(result[0]{0});
    double stepT = result[1]{0};
    double mx_mg_span = result[2]{0};
    double scan_range = mx_mg_span * max(h_mx_mg0,v_mx_mg0) / 100.0;
    double mx_mg_step = -1.0 * scan_range / double(nMagnet);
    //Starting scan values
    h_mx_mg0 = h_mx_mg0 - mx_mg_step * double(nMagnet) / 2.0;
    v_mx_mg0 = v_mx_mg0 - mx_mg_step * double(nMagnet) / 2.0;
    //
    //Set magnets to starting value to do backend tuning
    Set_Magnet_current_proc_fm(h_mx_mg0,v_mx_mg0);
    //
    //Tune attenuators of backends before magnet tuning
    int magtune_delay = 0;
    //Perform tuning: check which backend shall be used
    if(backend_code == "WBS") {
        // Get target
        result = ConfigurationReader("name_configwbs",["tune_target_magnet"],band,lo_freq);
        int tune_target_magnet = iround(result[0]{0});
        Tune_WBS_aot(band,tune_target_magnet);
        //
        Hifi_HIFI_Tune_mxmgc_useWBS($BBID,stepT,nMagnet,h_mx_mg0,v_mx_mg0,mx_mg_step);
        //Compute delay
        magtune_delay = iceil(1.0 + 0.94 + double(nMagnet) * (stepT + 1.05));
        //according to OBS 4.4
    } else {
        Tune_HRS_aot(band);
        //
        Hifi_HIFI_Tune_mxmgc_useHRS($BBID,stepT,nMagnet,h_mx_mg0,v_mx_mg0,mx_mg_step);
        magtune_delay = iceil(1.0 + 0.072 + double(nMagnet) * (stepT + 0.132));
        //according to OBS 4.4
    }
    //
    delay(magtune_delay);
    //debug_print(magtune_delay);
    //Set mixer bias back to nominal value at frequency of interest
    Mixerbias(normal_bias_h,normal_bias_v);
    //
}

//HIFI-COP-3-Stab-1
procedure Stab_COP_proc_ops {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string stab = "sys" in ["sys","lsw","int","dbs","fsw","stab"]; //category of stability measurement
    int freq_index = 1; //Frequency index to be applied
    int throw_index = 1; //FSW throw index to be applied
    string[] hrs_mode = ["wb1","wb1"];
    int integ_time = 4;
    double chop_phase = 1.0;
    string shutter = "open";
}{
    //Variable declaration
    string chopmode = "slowchop";
    double band_nb = GetBandCode(band);
    int n = 900;
    string backend = "both";
    //  
    //Get the list of frequencies to be used for the scan
    string tab = "config_stabfreq_" + band + ".config";
    int total = table_size(tab);
    double stabfreq = 0.0;
    int time_systab = 0;
    int time_stabil = 20;
    //
    if(stab == "stab") {
        //
        stabfreq = dlookup(tab,"1","freq_sys");
        Init_MSA_HBB_fm(band,"CLOSE",stabfreq,"ON");
        //
        LCU_switchon_proc_fm(band);
        //
        LO_tuning_block_fm(band,stabfreq);
        HRS_config_block_fm(band,hrs_mode);
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
        HRS_tune_block_fm(band);
        //
        chopmode = "tp";
        n = time_stabil * 60 / integ_time + 1;
        // 
        Proc_stability_intcold(band,n,hrs_mode,integ_time,backend,chopmode,chop_phase);
    }
    //
    //Get frequency corresponding to index freq_index
    if(stab != "stab") {
        stabfreq = dlookup(tab,"" + freq_index,"freq_" + stab);
    }
    time_systab = iround(dlookup(tab,"" + freq_index,"tsystab"));
    //Only deal with non-zero entries
    if(stabfreq != 0.0) {
        //
        if(stab == "int") {
            n = 450;
            //     
            Init_MSA_HBB_fm(band,"CLOSE",stabfreq,"ON");
            LO_tuning_block_fm(band,stabfreq);
            WBS_calib_fm(band);
            WBS_tune_proc_fm(band);
            HRS_tune_block_fm(band);
            // 
            Proc_stability_intcold_inthot(band,n,hrs_mode,integ_time,backend,chopmode,chop_phase);
        }
        //
        if(stab == "lsw") {
            n = 450;
            //     
            Init_MSA_CBB_fm(band,"CLOSE",stabfreq,"ON");
            LO_tuning_block_fm(band,stabfreq);
            WBS_calib_fm(band);
            WBS_tune_proc_fm(band);
            HRS_tune_block_fm(band);
            // 
            Proc_stability_intcold_exthot(band,n,hrs_mode,integ_time,backend,chopmode,chop_phase);
        }
        //
        if(stab == "sys") {
            //Start with 4min fast HRS sampling
            double sampling_rate = 3.0;
            //Sampling rate: 2 (2 HRS-H + 2 HRS-V), 4 (HRS-H + HRS-V, 2 HRS-H or 2 HRS-V) or 8 (1 HRS-H or 1 HRS-V) Hz
            double hrs_h_1 = 7.4;
            //Position in IF of HRS-H sub-band 1
            double hrs_h_2 = 7.4;
            //Position in IF of HRS-H sub-band 2
            double hrs_v_1 = 7.4;
            //Position in IF of HRS-V sub-band 1
            double hrs_v_2 = 7.4;
            //Position in IF of HRS-V sub-band 2
            double[] hrs_subband = [hrs_h_1,hrs_h_2,hrs_v_1,hrs_v_2];
            string hrs_polarization = "B";
            //HRS polarization: selection works only for 4 and 8 Hz
            n = 960;
            backend = "hrs";
            //     
            Init_MSA_HBB_fm(band,"CLOSE",stabfreq,"ON");
            LO_tuning_block_fm(band,stabfreq);
            // 
            if(band_nb > 10.0) {
                Stability_fast_proc_fm(band,n,hrs_subband,sampling_rate,hrs_polarization);
            }
            //
            chopmode = "tp";
            n = time_systab * 60 / integ_time;
            // 
            HRS_config_block_fm(band,hrs_mode);
            WBS_calib_fm(band);
            WBS_tune_proc_fm(band);
            HRS_tune_block_fm(band);
            Proc_stability_intcold(band,n,hrs_mode,integ_time,backend,chopmode,chop_phase);
        }
        //
        if(stab == "fsw") {
            chopmode = "fsw";
            n = 225;
            //    
            Init_MSA_HBB_fm(band,"CLOSE",stabfreq,"ON");
            //Look at HBB for further tuning - then move to SKY
            //LO and backend tunings are done later when tuning FSW1 and FSW2
            //LO_tuning_block_fm (band,stabfreq);
            //WBS_calib_fm(band) ;
            //WBS_tune_proc_fm(band);  
            //HRS_tune_block_fm(band);
            // 
            //For FSW, the throw is obtained by index
            //Retrieve frequency throws from LUT
            string tabfsw = "config_freqthrow.config";
            double bandnb = GetBandCode(band);
            double freq_throw = dlookup(tabfsw,"" + iceil(bandnb),"freq_throw_" + throw_index);
            if(freq_throw != 0.0) {
                //Check that frequencies to switch are not far by more than 1 index
                Check_FSW_index_proc_fm(band,stabfreq - freq_throw / 2000.0,stabfreq + freq_throw / 2000.0);
                Proc_stability_freqswitch_COP(band,stabfreq,freq_throw,n,hrs_mode,integ_time,backend,freq_index);
            }
            //For one freq. in 1a, 3a, 6a and 7b, the FSW on the CBB is performed
            string tabfswcbb = "config_stabfreq_fsw_CBB.config";
            double fsw_cbb_freq = dlookup(tabfswcbb,"" + iceil(bandnb),"freq_fsw");
            double freq_throw_cbb = dlookup(tabfswcbb,"" + iceil(bandnb),"freq_throw_" + throw_index);
            if(fsw_cbb_freq == stabfreq && freq_throw_cbb == freq_throw) {
                int n_cbb = n;
                if(bandnb < 6.0) {
                    //only 15 min
                    n_cbb = n / 2;
                }
                Proc_stability_freqswitch_COP_CBB(band,stabfreq,freq_throw,n_cbb,hrs_mode,integ_time,backend);
            }
            //
        }
        //
        if(stab == "dbs") {
            n = 450;
            //     
            Init_MSA_HBB_fm(band,"CLOSE",stabfreq,"ON");
            LO_tuning_block_fm(band,stabfreq);
            WBS_calib_fm(band);
            WBS_tune_proc_fm(band);
            HRS_tune_block_fm(band);
            // 
            Proc_stability_dbs(band,n,hrs_mode,integ_time,backend,shutter,chopmode,chop_phase);
        }
        //
    }
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure PositionSwitch_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size 
    int n_int = 3; // number of data dumps for integration per chop phase
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int n_loadinterval = 10; // number of nods before a load measurement
    int loadlength = 21; // Load duration
    bool final_load = false; // Need for final load measurement
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    // Consistency checks are performed in the telescope procedure
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
        }
        if(state[0] == 7) {
            // OFF Integration
            HIFIConfigureContIntegration(data_time,n_int,band,lo_freq,backendreadoutparms);
            HIFIContOffIntegration(data_time,n_int,rates);
            // Does a nod slew follow? occurs for odd cycle numbers
            if(state[2] % 2 == 1 && state[2] % n_loadinterval > 0) {
                HIFIActiveHK("normal",tnodslew);
            }
        }
        if(state[0] == 3) {
            // ON integration
            HIFIConfigureContIntegration(data_time,n_int,band,lo_freq,backendreadoutparms);
            HIFIContOnIntegration(data_time,n_int,rates);
            // Does a nod slew follow? occurs for even cycle numbers
            if(state[2] % 2 == 0 && state[2] % n_loadinterval > 0) {
                HIFIActiveHK("normal",tnodslew);
            }
        }
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
        }
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            HIFICloseObs();
        }
    }
}

// General parameter scan, procedure
// Allows to check sensitivity or stability in a range of
// user-input parameters
procedure Parameter_Scan_Investigation_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string param_scan = "DIPL" in ["DIPL","MAG","MBIAS","VDRAIN2"]; //The parameter to scan: DIPL, MAG, MBIAS, VDRAIN2
    double[] param_scan_input = [0.0,10.0,0.0,10.0,1.0]; //Min., Max and step value for parameter to be scanned
    string measurement_type = "NOISE" in ["NOISE","STAB","IFPOWER"]; //Type of measurement: NOISE (hotcold), IFPOWER (total power meast) or STAB (stability on CBB)
    int integ_time = 4; //Integration time PER PHASE for the HotCold measurement  
    int n = 100; //The number of 1sec integrations in case of Stability
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "tp" in ["tp","slowchop","fastchop"]; //modulation mode between hot/cold: tp, slowchop, fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    //Move chopper to hot source
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectroscopy according to the chopmode for hotcold
    int[] res = [0,0];
    int n_wbs1 = 0;
    int n_hrs_trans = 0;
    int total_time = 0;
    //
    if(chopmode == "tp") {
        res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
        total_time = res[0] * res[1];
    }
    if(chopmode == "slowchop") {
        res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
        total_time = res[0] * res[1];
    }
    if(chopmode == "fastchop") {
        //Integ_time expected here is the TOTAL integration time with both phases + residual HRS time
        res = Configure_Spectrometer_fast_chop_proc_fm(band,integ_time * 2,chop_phase,hrs_mode,backend);
        total_time = iceil(chop_phase * double(res[1] * res[2]));
        //debug_print("Fast chop parameters: n_wbs1 = "+res[2]+", n_hrs_trans = "+res[3]);
        n_wbs1 = res[2];
        n_hrs_trans = res[3];
    }
    //
    //Start loop on parameter. 
    //We assume backends + FPU + LO are all setup at the frequency of interest
    //
    double param_current_value_H = param_scan_input[0];
    double param_current_value_V = param_scan_input[2];
    int step_H = 1;
    int step_V = 1;
    if(param_scan_input[4] != 0.0) {
        step_H = iceil((param_scan_input[1] - param_scan_input[0]) / param_scan_input[4]);
        step_V = iceil((param_scan_input[3] - param_scan_input[2]) / param_scan_input[4]);
    }
    if(step_H > step_V) {
        error("The step size and the respective parameters chosen imply more steps for H than for V. Please adjust to get the same amount of steps.");
    }
    if(step_V > step_H) {
        error("The step size and the respective parameters chosen imply more steps for V than for H. Please adjust to get the same amount of steps.");
    }
    while(param_current_value_H <= param_scan_input[1]) {
        //Check parameter type
        if(param_scan == "DIPL") {
            //Diplexer scan
            //Set diplexer current
            Hifi_HIFI_CH1_DPACT_C($BBID,param_current_value_H);
            Hifi_HIFI_CV1_DPACT_C($BBID,param_current_value_V);
            delay(1);
        }
        if(param_scan == "MBIAS") {
            //mixer bias scan
            //Set mixer bias
            Mixerbias(param_current_value_H,param_current_value_V);
        }
        if(param_scan == "MAG") {
            //magnet scan
            //Set magnet current
            //If first setting, set to max. first
            if(param_current_value_H == param_scan_input[0]) {
                {double,string}[] result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
                Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
                Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
                delay(1);
            }
            //set to current value
            Hifi_HIFI_CH1_MX_MG_C($BBID,param_current_value_H);
            Hifi_HIFI_CV1_MX_MG_C($BBID,param_current_value_V);
            delay(1);
        }
        if(param_scan == "VDRAIN2") {
            //Drain2 voltage scan
            LCU_config_nominal_w_D2_proc_fm(band,lo_freq,param_current_value_H);
        }
        //
        //Measurement
        //
        if(measurement_type == "NOISE") {
            //HotCold
            //
            //Noise temperature measurement 
            Hot_cold(band,hrs_mode,backend,integ_time,chopmode,n_wbs1,n_hrs_trans);
            //
        }
        if(measurement_type == "IFPOWER") {
            //Simple total power measurement
            if(chopmode != "tp") {
                error("Option IFPOWER cannot be used in chopped mode. Please use total power (tp)");
            } else {
                Spectro_total_power_block_fm(band,res,backend);
                //Integration is done
            }
        }
        if(measurement_type == "STAB") {
            //Stability
            //Noise temperature measurement: removed since 9.15.1.
            //Hot_cold(band,hrs_mode,backend,total_time,chopmode,n_wbs1,n_hrs_trans);
            //Stability measurement on cold internal source
            //Total power stability measurement: WBS only, 2sec. for B1-5, 1sec for B6-7 TP
            if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
                //Stability_intcold_fm (band,n,2,"wbs",hrs_mode,chopmode);
                Stability_intcold_fm(band,n,integ_time,backend,hrs_mode,chopmode,chop_phase);
            } else {
                //Stability_intcold_fm (band,n,1,"wbsFast2",hrs_mode,chopmode);
                Stability_intcold_fm(band,n,integ_time,backend,hrs_mode,chopmode,chop_phase);
            }
            //          
        }
        //increase parameter
        param_current_value_H = param_current_value_H + param_scan_input[4];
        param_current_value_V = param_current_value_V + param_scan_input[4];
        //Case of step = 0: need to avoid infinite loop
        if(param_scan_input[4] == 0.0) {
            param_current_value_H = param_current_value_H + 1000.0;
            param_current_value_V = param_current_value_V + 1000.0;
        }
    }
    //
}

//Generic procedure for slowchop using the adequate instrument side
//It also converts prime voltage into redundant voltage
procedure HIFI_Spectr_slow_chop_proc_fm {
    double chop_angle1 = 0.0;
    double chop_angle2 = 0.0;
}{
    //Convert prime voltage into redundant voltage
    chop_angle1 = Check_Chopper_Prime_Redundant(chop_angle1);
    chop_angle2 = Check_Chopper_Prime_Redundant(chop_angle2);
    //check prime or redundant keyword
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant"],"0",0.0);
    if(result_d[0]{1} == "prime") {
        Hifi_HIFI_P_Spectr_slow_chop($BBID,chop_angle1,chop_angle2);
    } else {
        Hifi_HIFI_R_Spectr_slow_chop($BBID,chop_angle1,chop_angle2);
    }
    //
}

{string,double,double}[] procedure HifiSScanModeFSwitchSequencerInit {
    string modeName = "fs-freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_switch_off = 1 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hr1{0},hr1{1},hr1{3}},{hr2{0},hr2{1},hr2{3}},wb1,wb2};
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    // Now general part of Frequency switch modes
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {double,double,double,double} phaselengths = FSwitchPhaseLengths(band,lo_freq,effResolution,narrowReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // How much time for single ON phase
    int n_switch_on_guess = imax(iceil(2.0 * phaselengths{0} / ((double(n_freq_point_guess) + sqrt(double(n_freq_point_guess))) * 2.0 * double(data_time_guess))),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) * sqrt(double(n_freq_point_guess)) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)},{"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)}];

    return retvalues;
}

//General script to read TM1, TM2,etc, procedure
procedure LCU_Read_TM_pages_OLD_proc_fm {
}{
    //Re-implement old way to be consistent with MOIS manual procedures
    //
    //Get various TM pages. This will clear error flags too
    //Hifi_HIFI_LCU_all_tuning_hk();
    //delay(2);
    /////////////////////////////////////
    //Temporary work-around for TVTB SFT
    //Get various TM pages
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM1");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM2");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM3");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_G");
    delay(2);
    //
    //Clear error flags
    Hifi_HIFI_LCU_Single($BBID,"HL_CLR_ERR");
    //
}

/////////////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the OTF observing mode
{double,double,double,double,double} procedure OTFmap_noisecomputer {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    int nlines_tot = 1; // Number of rows in the map
    int npoints = 10; // Number of data dumps per row
    int n_supersample = 1; // Supersamplingfactor
    int n_linesperscan = 2; // Number of lines between two OFFs
    int n_cover = 1; // Number of map coverages
    int tslew = 20; // Minimum time between OFF and point
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double} tact = {10.0,4.0,12.0}; // field of actual timings
}{
    // The sum of drift noise and radiometric noise is computed.
    //
    double tdead = tact{0};
    // Average dead time in one slew
    double tint_act = tact{1};
    // integration time excluding all dead times
    double tintoff = tact{2};
    // integration time on OFF
    // Get parameters which are needed
    double tsys = InterpolateTsys(band,lo_freq);
    double eta_mb = InterpolateCoupling(band,lo_freq);
    double[] gssb = InterpolateGssb(band,lo_freq);
    // Get the drift parameters to compute the drift noise
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double allan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // Noise computation and OFF integration depends on the number of really
    // independent points - different treatment for repeated scans of same line
    double scanpoints = double(n_linesperscan * npoints);
    double qval = tintoff / (sqrt(scanpoints) * tint_act);
    if(nlines_tot == 1 && n_linesperscan > 1) {
        // Get actual noise
        // This is returned twice: for both limiting resolutions
        double systemnoise_lores = OtfRepeatedNoise(double(n_linesperscan),scanpoints,[tint_act / allan_time_lores,tdead / allan_time_lores,double(tslew) / allan_time_lores,qval,alpha]);
        double systemnoise_hires = OtfRepeatedNoise(double(n_linesperscan),scanpoints,[tint_act / allan_time_hires,tdead / allan_time_hires,double(tslew) / allan_time_hires,qval,alpha]);
        double noiserat = OtfRepeatedNoiseRatio(double(n_linesperscan),scanpoints,[tint_act / allan_time_lores,tdead / allan_time_lores,double(tslew) / allan_time_lores,qval,alpha]);
    } else {
        // Get actual noise
        systemnoise_lores = OtfNoise(scanpoints,[tint_act / allan_time_lores,tdead / allan_time_lores,double(tslew) / allan_time_lores,qval,alpha]);
        systemnoise_hires = OtfNoise(scanpoints,[tint_act / allan_time_hires,tdead / allan_time_hires,double(tslew) / allan_time_hires,qval,alpha]);
        noiserat = OtfNoiseRatio(scanpoints,[tint_act / allan_time_lores,tdead / allan_time_lores,double(tslew) / allan_time_lores,qval,alpha]);
    }
    // Renormalize
    systemnoise_lores = systemnoise_lores * scanpoints / (tscan * double(n_cover));
    systemnoise_hires = systemnoise_hires * scanpoints / (tscan * double(n_cover));
    // Compute total double sideband noise 
    double dsbnoise_lores = tsys * sqrt(systemnoise_lores / (eff_resolution{1} * 1000000.0));
    double dsbnoise_hires = tsys * sqrt(systemnoise_hires / (eff_resolution{0} * 1000000.0));
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Get single sideband noise equivalent
    double usbnoise_lores = dsbnoise_lores / gssb[0];
    double usbnoise_hires = dsbnoise_hires / gssb[0];
    double lsbnoise_lores = dsbnoise_lores / gssb[1];
    double lsbnoise_hires = dsbnoise_hires / gssb[1];
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiserat};
}

// Change mixer bias
block Mixerbias_block_fm HIFI 3205 {
    double bias_h = 0.0;
    double bias_v = 0.0;
}{
    //Start_block() ;   
    Mixerbias(bias_h,bias_v);
}

// Generic A_M function
// DT/MB - 3 June 2005
int[] procedure GetA_M {
    double flo = 15.0; // Input HRS internal LO freq. in GHz
}{
    // First guess of M
    int m = iround(flo / 200.0 - 1.0);
    int a = iround((flo - 200.0 * (double(m) + 1.0)) / 20.0);
    //
    // Adjust
    if(a < 0) {
        m = m - 1;
        a = iround((flo - 200.0 * (double(m) + 1.0)) / 20.0);
    }
    //
    int[] a_m = [a,m];

    return a_m;
}

// HRS partial configuration, procedure
// Configures the resolution mode
procedure HRS_config_resol_fm {
    string band = "4a"; // HIFI band
    string[] hrs_mode = ["wb","wb"]; //HRS resolution code
}{
    ////////////////////////////////////////////////////////////////////
    //Now Configure blocks
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_block_1","hrh_block_2","hrh_block_3","hrh_block_4","hrh_block_5","hrh_block_6","hrh_block_7","hrh_block_8"],band,0.0);
    string hrh_block_1 = result[0]{1};
    string hrh_block_2 = result[1]{1};
    string hrh_block_3 = result[2]{1};
    string hrh_block_4 = result[3]{1};
    string hrh_block_5 = result[4]{1};
    string hrh_block_6 = result[5]{1};
    string hrh_block_7 = result[6]{1};
    string hrh_block_8 = result[7]{1};
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrh_block_1,hrh_block_2,hrh_block_3,hrh_block_4,hrh_block_5,hrh_block_6,hrh_block_7,hrh_block_8);
    //delay(hrs_config_delay);
    //
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_block_1","hrv_block_2","hrv_block_3","hrv_block_4","hrv_block_5","hrv_block_6","hrv_block_7","hrv_block_8"],band,0.0);
    string hrv_block_1 = result[0]{1};
    string hrv_block_2 = result[1]{1};
    string hrv_block_3 = result[2]{1};
    string hrv_block_4 = result[3]{1};
    string hrv_block_5 = result[4]{1};
    string hrv_block_6 = result[5]{1};
    string hrv_block_7 = result[6]{1};
    string hrv_block_8 = result[7]{1};
    //
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrv_block_1,hrv_block_2,hrv_block_3,hrv_block_4,hrv_block_5,hrv_block_6,hrv_block_7,hrv_block_8);
    //
    //Wait delay to allow all setting to be configured
    delay(hrs_config_delay);
}

//Generic procedure to launch engineering scan applied to chopper rotation, procedure
procedure Engineering_scan_for_closed_loop_scan_ops {
    double targetAngle = 0.0; //Target chopper voltage
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50]; // HIF_N_samples_1
    int samplesAfter = 1000 in [0,1000]; // HIF_N_samples_2
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red 
}{
    //
    if(prime_or_redundant == "Prime") {
        Hifi_HIFI_P_Chopper_scan_fast(milliSecSample,targetAngle,samplesBefore,samplesAfter);
    } else {
        Hifi_HIFI_R_Chopper_scan_fast(milliSecSample,targetAngle,samplesBefore,samplesAfter);
    }
    //
    // delay calculation
    int nb_HK = 1;
    //For this TC, the 2 last HK fields are blanked out
    int millisecondsUsed = 1000 + 10 + milliSecSample * nb_HK * (samplesBefore + samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //
}

// Single integration at OFF position for a specified time
block HIFIContOffIntegration HIFI 6021 {
    int n_int = 1; // Integration time counter
    int data_time = 4; // Integration time between two data readouts
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_tp_proc_aot(n_int,data_time,rates);
}

// Interpolate total power system Allan time and exponent
double[] procedure InterpolateTpAllan {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    bool subband = false; // 1GHz bandwith reference instead of full IF
}{
    if(subband) {
        double[] allan = CalibrationReader("system_Allan_subband",["tp_Allan_time","tp_Allan_exp","tp_binning_exp"],band,lo_freq);
    } else {
        allan = CalibrationReader("system_Allan",["tp_Allan_time","tp_Allan_exp","tp_binning_exp"],band,lo_freq);
    }

    return allan;
}

// BLOCK : Functional Test No 4 (HRS Scan the HRS Attenuators)
block HRS_functional_test_No_4_block_fm HIFI 3640 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    int repeats = 32;
    double hrsH_attenuators_value = 15.5;
    double hrsV_attenuators_value = 15.5;
    //Test is done in WB mode
    string hrsh_blocks_configuration = "corr_wide";
    string hrsv_blocks_configuration = "corr_wide";
    // Configure spectroscopy
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    // Configure blocks
    //=================
    //H-polar
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration,hrsh_blocks_configuration);
    // 
    //delay(1);
    //V-polar
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration,hrsv_blocks_configuration);
    // 
    delay(1);
    //
    // Fetch internal LO settings
    //===========================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    double[] hrsH_LO = [result[1]{0},result[2]{0},result[3]{0},result[4]{0},result[5]{0},result[6]{0},result[7]{0}];
    string hrs_polarization_h = result[0]{1};
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    double[] hrsV_LO = [result[1]{0},result[2]{0},result[3]{0},result[4]{0},result[5]{0},result[6]{0},result[7]{0}];
    string hrs_polarization_v = result[0]{1};
    //
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    //
    // Loops on the different configurations of the HRS attenuators
    //===============================================
    for(int i = 0 .. repeats - 1) {
        //=======================================
        Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_attenuators_value,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
        // 
        //delay(2);
        Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_attenuators_value,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
        // 
        delay(1);
        // Take a spectrum
        //================
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //Delay To be sure that the Spectr_total_power finished
        //==========================================
        //
        // Change the value of the 8 attenuators
        //==============================
        hrsH_attenuators_value = hrsH_attenuators_value - 0.5;
        hrsV_attenuators_value = hrsV_attenuators_value - 0.5;
    }
}

////////////////////////////////////
// OTF load chop observing mode without baseline calibration
// 
{string,double,double}[] procedure HifiMappingProcLoadChopOTFNoRefSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints = 10 in [1,720]; // Number of data dumps per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period defines number of lines between two loads
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(0.3 * allan_time_lores),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // n_switch limited by load_interval - 2 lines should be possible
    int n_switch_on_guess = load_interval / (4 * npoints * data_time_guess);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // Contruct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)}];

    return retvalues;
}

//////////////////////////////////////////////////////////////////
// HRS complete configuration with maximum attenuation, block
// Both polarizations are treated
block HRS_config_max_att_block_aot HIFI 6634 {
    string band = "4a"; // HIFI band
    string[] hrs_mode = ["wb","wb"]; //HRS resolution code
}{
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrh_up_ol1_m = a_m_parameter[1];
    int hrh_up_ol1_a = a_m_parameter[0];
    int hrh_up_ol2_m = a_m_parameter[3];
    int hrh_up_ol2_a = a_m_parameter[2];
    int hrh_up_ol3_m = a_m_parameter[5];
    int hrh_up_ol3_a = a_m_parameter[4];
    int hrh_up_ol4_m = a_m_parameter[7];
    int hrh_up_ol4_a = a_m_parameter[6];
    int hrh_down_ol5_m = a_m_parameter[9];
    int hrh_down_ol5_a = a_m_parameter[8];
    int hrh_down_ol6_m = a_m_parameter[11];
    int hrh_down_ol6_a = a_m_parameter[10];
    int hrh_down_ol7_m = a_m_parameter[12];
    //V-polar
    int hrv_up_ol1_m = a_m_parameter[14];
    int hrv_up_ol1_a = a_m_parameter[13];
    int hrv_up_ol2_m = a_m_parameter[16];
    int hrv_up_ol2_a = a_m_parameter[15];
    int hrv_up_ol3_m = a_m_parameter[18];
    int hrv_up_ol3_a = a_m_parameter[17];
    int hrv_up_ol4_m = a_m_parameter[20];
    int hrv_up_ol4_a = a_m_parameter[19];
    int hrv_down_ol5_m = a_m_parameter[22];
    int hrv_down_ol5_a = a_m_parameter[21];
    int hrv_down_ol6_m = a_m_parameter[24];
    int hrv_down_ol6_a = a_m_parameter[23];
    int hrv_down_ol7_m = a_m_parameter[25];
    //Attenuators are fixed
    //H-polar
    double hrh_1u_att = 15.5;
    double hrh_1l_att = 15.5;
    double hrh_2u_att = 15.5;
    double hrh_2l_att = 15.5;
    double hrh_3u_att = 15.5;
    double hrh_3l_att = 15.5;
    double hrh_4u_att = 15.5;
    double hrh_4l_att = 15.5;
    //V-polar    
    double hrv_1u_att = 15.5;
    double hrv_1l_att = 15.5;
    double hrv_2u_att = 15.5;
    double hrv_2l_att = 15.5;
    double hrv_3u_att = 15.5;
    double hrv_3l_att = 15.5;
    double hrv_4u_att = 15.5;
    double hrv_4l_att = 15.5;
    //Configure HRS-H
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrh_1u_att,hrh_1l_att,hrh_2u_att,hrh_2l_att,hrh_3u_att,hrh_3l_att,hrh_4u_att,hrh_4l_att,hrh_up_ol1_m,hrh_up_ol1_a,hrh_up_ol2_m,hrh_up_ol2_a,hrh_up_ol3_m,hrh_up_ol3_a,hrh_up_ol4_m,hrh_up_ol4_a,hrh_down_ol5_m,hrh_down_ol5_a,hrh_down_ol6_m,hrh_down_ol6_a,hrh_down_ol7_m);
    //delay(hrs_config_delay);
    //
    //Configure HRS-V
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrv_1u_att,hrv_1l_att,hrv_2u_att,hrv_2l_att,hrv_3u_att,hrv_3l_att,hrv_4u_att,hrv_4l_att,hrv_up_ol1_m,hrv_up_ol1_a,hrv_up_ol2_m,hrv_up_ol2_a,hrv_up_ol3_m,hrv_up_ol3_a,hrv_up_ol4_m,hrv_up_ol4_a,hrv_down_ol5_m,hrv_down_ol5_a,hrv_down_ol6_m,hrv_down_ol6_a,hrv_down_ol7_m);
    delay(hrs_config_delay);
    //
    //Now Configure blocks
    HRS_config_resol_fm(band,hrs_mode);
}

// Standing wave study for FSW model
//HIFI-COP-X-StWv-FSW
procedure StWv_FSW_COP_proc_ops {
    string band = "1a"; // HIFI band
}{
    double bandnb = GetBandCode(band);
    //Retrieve frequencies from LUT: depends on whether this is diplexer or beamsplitter
    if(bandnb < 5.0 || bandnb == 9.0 || bandnb == 10.0) {
        string tabstwv = "config_stabfreq_" + band + ".config";
        //"config_stwv_fsw_bs.config";
        int nb_freq_st = 3;
        int nb_freq_end = 4;
        //Special case of band 5b: only 2 first frequencies
        if(bandnb == 10.0) {
            nb_freq_st = 1;
            nb_freq_end = 2;
        }
        string column_name = "freq_fsw";
    } else {
        tabstwv = "config_stwv_fsw_dip.config";
        nb_freq_st = 1;
        nb_freq_end = 16;
        column_name = "lo_freq_" + band;
    }
    //
    //General parameters for scan
    double step = 0.015;
    //GHz
    int total_stepnb = 21;
    double stepnb = double(total_stepnb / 2);
    double[] lo_freq_input = [0.0,0.0,0.0];
    //Loop on frequencies
    for(int i = nb_freq_st .. nb_freq_end) {
        double lo_freq = dlookup(tabstwv,"" + i,column_name);
        message(band + ", " + lo_freq);
        //Switch-on FPU on BB
        Init_MSA_CBB_fm(band,"CLOSE",lo_freq,"ON");
        //Build lo_freq_input array
        lo_freq_input = [lo_freq - stepnb * step,lo_freq + stepnb * step,step];
        Standing_wave_nospectra_fm_COP(band,lo_freq_input);
    }
    //
}

//TM to control heater values of LOU, procedure
procedure HL_heater_proc_aot {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band.
    string context = "nominal" in ["nominal","stby"]; //whether heater applies to stby or nominal context
}{
    double[] cresult = CalibrationReader("name_loheater",["heater_nominal","heater_stby"],band,0.0);
    double hifi_HL_heater = cresult[0];
    if(context == "stby") {
        hifi_HL_heater = cresult[1];
    }
    Hifi_HIFI_HL_heater($BBID,hifi_HL_heater);
}

//Set DC bias without switching on the chain, block
//All input parameters shall be given by the user
block View_SafetyTablePage_block_fm HIFI 3665 {
    string band = "1a" in ["ALL","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int freq_index = 0 in [0,31]; //frequency index
}{
    //
    //Start_block();
    //Switch to diagnostic
    {double,string}[] result = ConfigurationReader("name_delays",["set_to_nominal_delay"],"0",0.0);
    int set_to_nominal_delay = iround(result[0]{0});
    //
    Hifi_HIFI_HL_Diagnostic($BBID);
    delay(set_to_nominal_delay);
    //Read safety table
    string band_new = Translate_band_name(band);
    Hifi_HIFI_non_periodic_hk_LCU(freq_index,"channel_" + band_new);
    delay(1);
    //Switch back to nominal
    Hifi_HIFI_HL_Normal($BBID);
    delay(set_to_nominal_delay);
    //
}

// Stability test, procedure, only backends
// Here for dummy/warm context
procedure Proc_stability_backend {
    string band = "1a"; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Band0 setting
    Band0_fm("0","OPEN");
    //Band0_hbb_on_fm("0","CLOSE");
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        //Configure and tune backends
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        //Configure and tune backends
        HRS_config_min_att_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration: done later
    //Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);	//2 sec. integration
    //
    Stability_backend_fm(band,n,integ_time,backend,hrs_mode);
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
}

//////////////////////////////////////////////////////////////////////
// Determine data readout period and corresponding data rate
{int,double[]} procedure AllDataRates {
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
    int data_time = 4; // Integration time between two data readouts
    bool mode16bits = true; // whether WBS is used in 16bit mode
}{
    // Definitions - read from calibration file:
    // WBS
    if(mode16bits) {
        int wbit = ifloor(dlookup("datarates","wbsbitnormal","value"));
        int nchannelwbs = ifloor(dlookup("datarates","nchannelwbsnormal","value"));
    } else {
        wbit = ifloor(dlookup("datarates","wbsbithigh","value"));
        nchannelwbs = ifloor(dlookup("datarates","nchannelwbshigh","value"));
    }
    // HRS=24 bit
    int hbit = ifloor(dlookup("datarates","hrsbit","value"));
    int nchannelhrs = ifloor(dlookup("datarates","nchannelhrs","value"));
    // Maximum data rate
    int pmax = ifloor(dlookup("datarates","maxbuspackets","value"));
    int osize = ifloor(dlookup("datarates","packetoverhead","value"));
    // Check with periodic HK
    {string,int,double,double,double,double} hkparms = PeriodicHKParms("normal");
    int hkpackets = iceil(hkparms{2} + hkparms{4});
    pmax = pmax - hkpackets;
    // Dead packets
    int deadstartpackets = iceil(dlookup("datarates","dead_startpackets","value"));
    int deadifpackets = iceil(dlookup("datarates","dead_ifpackets","value"));
    int deadwbsstartsize = iceil(dlookup("datarates","dead_wbsstartsize","value"));
    int deadwbsifsize = iceil(dlookup("datarates","dead_wbsifsize","value"));
    int deadhrsstartsize = iceil(dlookup("datarates","dead_hrsstartsize","value"));
    int deadhrsifsize = iceil(dlookup("datarates","dead_hrsifsize","value"));
    // sum up channels
    int n_wchannels = 0;
    int packets = 0;
    int allbits = 0;
    int allhkbits = 0;
    int newpackets = 0;
    // First HRS
    {int,int,int,int} hrssets = HrsSubbandSelection(backendreadoutparms);
    int n_hchannels = hrssets{2};
    int n_vchannels = hrssets{3};
    if(n_hchannels > 0) {
        newpackets = deadstartpackets + (n_hchannels + nchannelhrs - 1) / nchannelhrs;
        allbits = allbits + n_hchannels * hbit + newpackets * osize + deadhrsstartsize;
        allhkbits = allhkbits + deadhrsifsize + deadifpackets * osize;
        packets = packets + newpackets + deadifpackets;
    }
    if(n_vchannels > 0) {
        newpackets = deadstartpackets + (n_vchannels + nchannelhrs - 1) / nchannelhrs;
        allbits = allbits + n_vchannels * hbit + newpackets * osize + deadhrsstartsize;
        allhkbits = allhkbits + deadhrsifsize + deadifpackets * osize;
        packets = packets + newpackets + deadifpackets;
    }
    // Now the WBS channels
    int maxbands = 4;
    // First WBS
    if(backendreadoutparms{2}{0}) {
        n_wchannels = 0;
        newpackets = 0;
        for(int i2 = 1 .. maxbands) {
            int newchannels = backendreadoutparms{2}{1}[i2 - 1][1] - backendreadoutparms{2}{1}[i2 - 1][0];
            newpackets = newpackets + (newchannels + nchannelwbs - 1) / nchannelwbs;
            n_wchannels = n_wchannels + newchannels;
        }
        newpackets = deadstartpackets + newpackets;
        allbits = allbits + n_wchannels * wbit + newpackets * osize + deadwbsstartsize;
        allhkbits = allhkbits + deadwbsifsize + deadifpackets * osize;
        packets = packets + newpackets + deadifpackets;
    }
    // Second WBS
    if(backendreadoutparms{3}{0}) {
        n_wchannels = 0;
        newpackets = 0;
        for(int i3 = 1 .. maxbands) {
            newchannels = backendreadoutparms{3}{1}[i3 - 1][1] - backendreadoutparms{3}{1}[i3 - 1][0];
            newpackets = newpackets + (newchannels + nchannelwbs - 1) / nchannelwbs;
            n_wchannels = n_wchannels + newchannels;
        }
        newpackets = deadstartpackets + newpackets;
        allbits = allbits + n_wchannels * wbit + newpackets * osize + deadwbsstartsize;
        allhkbits = allhkbits + deadwbsifsize + deadifpackets * osize;
        packets = packets + newpackets + deadifpackets;
    }
    // Now compute minimum time;
    int tdatamin = (packets + pmax - 1) / pmax;
    if(tdatamin < 1) {
        CError("Internal error: Too low packet rate computed.");
    }
    // Data rates in bit/s are returned
    double sciencerate = double(allbits) / double(data_time);
    double stdhkrate = hkparms{3};
    double hkrate = stdhkrate + double(allhkbits) / double(data_time);

    return {tdatamin,[sciencerate,stdhkrate,hkrate]};
}

//////////////////////////////////////////////////////////////////
// HRS complete configuration with maximum attenuation, block
// Both polarizations are treated
block HRS_standby_block_ops HIFI 7633 {
    string band = "0"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_ops(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrh_up_ol1_m = a_m_parameter[1];
    int hrh_up_ol1_a = a_m_parameter[0];
    int hrh_up_ol2_m = a_m_parameter[3];
    int hrh_up_ol2_a = a_m_parameter[2];
    int hrh_up_ol3_m = a_m_parameter[5];
    int hrh_up_ol3_a = a_m_parameter[4];
    int hrh_up_ol4_m = a_m_parameter[7];
    int hrh_up_ol4_a = a_m_parameter[6];
    int hrh_down_ol5_m = a_m_parameter[9];
    int hrh_down_ol5_a = a_m_parameter[8];
    int hrh_down_ol6_m = a_m_parameter[11];
    int hrh_down_ol6_a = a_m_parameter[10];
    int hrh_down_ol7_m = a_m_parameter[12];
    //V-polar
    int hrv_up_ol1_m = a_m_parameter[14];
    int hrv_up_ol1_a = a_m_parameter[13];
    int hrv_up_ol2_m = a_m_parameter[16];
    int hrv_up_ol2_a = a_m_parameter[15];
    int hrv_up_ol3_m = a_m_parameter[18];
    int hrv_up_ol3_a = a_m_parameter[17];
    int hrv_up_ol4_m = a_m_parameter[20];
    int hrv_up_ol4_a = a_m_parameter[19];
    int hrv_down_ol5_m = a_m_parameter[22];
    int hrv_down_ol5_a = a_m_parameter[21];
    int hrv_down_ol6_m = a_m_parameter[24];
    int hrv_down_ol6_a = a_m_parameter[23];
    int hrv_down_ol7_m = a_m_parameter[25];
    //Attenuators are fixed
    //H-polar
    double hrh_1u_att = 15.5;
    double hrh_1l_att = 15.5;
    double hrh_2u_att = 15.5;
    double hrh_2l_att = 15.5;
    double hrh_3u_att = 15.5;
    double hrh_3l_att = 15.5;
    double hrh_4u_att = 15.5;
    double hrh_4l_att = 15.5;
    //V-polar    
    double hrv_1u_att = 15.5;
    double hrv_1l_att = 15.5;
    double hrv_2u_att = 15.5;
    double hrv_2l_att = 15.5;
    double hrv_3u_att = 15.5;
    double hrv_3l_att = 15.5;
    double hrv_4u_att = 15.5;
    double hrv_4l_att = 15.5;
    //Configure HRS-H
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrh_1u_att,hrh_1l_att,hrh_2u_att,hrh_2l_att,hrh_3u_att,hrh_3l_att,hrh_4u_att,hrh_4l_att,hrh_up_ol1_m,hrh_up_ol1_a,hrh_up_ol2_m,hrh_up_ol2_a,hrh_up_ol3_m,hrh_up_ol3_a,hrh_up_ol4_m,hrh_up_ol4_a,hrh_down_ol5_m,hrh_down_ol5_a,hrh_down_ol6_m,hrh_down_ol6_a,hrh_down_ol7_m);
    //delay(hrs_config_delay);
    //
    //Configure HRS-V
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrv_1u_att,hrv_1l_att,hrv_2u_att,hrv_2l_att,hrv_3u_att,hrv_3l_att,hrv_4u_att,hrv_4l_att,hrv_up_ol1_m,hrv_up_ol1_a,hrv_up_ol2_m,hrv_up_ol2_a,hrv_up_ol3_m,hrv_up_ol3_a,hrv_up_ol4_m,hrv_up_ol4_a,hrv_down_ol5_m,hrv_down_ol5_a,hrv_down_ol6_m,hrv_down_ol6_a,hrv_down_ol7_m);
    delay(hrs_config_delay);
    //
    //Now Configure blocks
    HRS_config_resol_proc_ops(band,hrs_mode);
    //Check attenuator values
    //Now checked at end of procedure during instrument mode status check
    //mois_tmcheck("Check that parameters HRH_1U_ATT, HRH_1L_ATT, HRH_2U_ATT, HRH_2L_ATT, HRH_3U_ATT, HRH_3L_ATT, HRH_4U_ATT and HRH_4L_ATT are set to 15.5");
    //mois_tmcheck("Check that parameters HRV_1U_ATT, HRV_1L_ATT, HRV_2U_ATT, HRV_2L_ATT, HRV_3U_ATT, HRV_3L_ATT, HRV_4U_ATT and HRV_4L_ATT are set to 15.5");    
    //Check LO locks and values
    //mois_tmcheck("Check that parameters HRH_LOCK_LO1_S, HRH_LOCK_LO2_S, HRH_LOCK_LO3_S, HRH_LOCK_LO4_S, HRH_LOCK_LO5_S, HRH_LOCK_LO6_S, and HRH_LOCK_LO7_S are all Locked");
    //mois_tmcheck("Check that parameters HRV_LOCK_LO1_S, HRV_LOCK_LO2_S, HRV_LOCK_LO3_S, HRV_LOCK_LO4_S, HRV_LOCK_LO5_S, HRV_LOCK_LO6_S, and HRV_LOCK_LO7_S are all Locked");
    //Check_HRS_LO_proc_ops([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],
    //						    hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],
    //						    hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
}

///////////////////////////////////////////////
// Generation of messages common to all observing modes
// opening for all messages
procedure OpenMessages {
    string modename = "HIFI-Point-PositionSwitch"; // identifier of obsmode
    {int,int,int,int,int,int,int,int,int,int} seq = {0,0,0,0,0,0,0,0,0,0}; // sequence parameters
}{
    message("<html><body>");
    message("<h1>Observing mode: " + modename + " executed</h1>");
    message("<h2>Sequence parameters</h2>");
    message("<p>");
    if(seq{0} != 0) {
        message("Backend readout period on source:<strong> " + seq{0} + "</strong>s<br>");
    }
    if(seq{1} != 0) {
        message("Backend readout period on OFF: <strong>" + seq{1} + "</strong>s<br>");
    }
    if(seq{2} != 0) {
        message("Number of continuous data dumps per source point: <strong>" + seq{2} + "</strong></strong><br>");
    }
    if(seq{3} != 0) {
        message("Number of switch cycles on source: <strong>" + seq{3} + "</strong><br>");
    }
    if(seq{4} != 0) {
        message("Number of cycles on OFF: <strong>" + seq{4} + "</strong><br>");
    }
    if(seq{5} != 0) {
        message("Number of lines between two OFF measurements: <strong>" + seq{5} + "</strong><br>");
    }
    if(seq{6} != 0) {
        message("Number of points in one nodding phase: <strong>" + seq{6} + "</strong><br>");
    }
    if(seq{7} != 0) {
        message("Number of frequencies to combine with one load: <strong>" + seq{7} + "</strong><br>");
    }
    if(seq{8} != 0) {
        message("Number of pointing cycles: <strong>" + seq{8} + "</strong><br>");
    }
    if(seq{9} != 0) {
        message("Interval between load measurements: <strong>" + seq{9} + "</strong>s<br>");
    }
    message("</p>");
    message("<p>");
}

// Stability test, procedure, double-beam-switch chop
// Differential stability between M3left and M3right. 
block Stability_dbs_fm HIFI 3435 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integration pairs 
    int integ_time = 4; //Total (co-added) integration time of ONE SINGLE phase in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "slowchop" in ["slowchop","fastchop"]; //Whether to use slowchop or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    Start_block();
    //Get chopper settings
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_M3left","chop_M3right"],band,0.0);
    double chop_left = result[0]{0};
    double chop_right = result[1]{0};
    //
    //We implement a special slow-chop spectroscopy between
    //internal cold and external hot
    if(chopmode == "slowchop") {
        Slow_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_left,chop_right);
    } else {
        Fast_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_left,chop_right,chop_phase);
    }
}

//HIFI LO tuning, block
//Special testmode to test influence of best guess and slope
block LO_tuning_investigation_block_fm HIFI 3674 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    double d2_v_middle = 2.0; //Best-guess for scan middle
    double scan_width = 10.0; //Total scan span in percentage of the best-guess
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    string mixer_polarization = result[0]{1};
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = scan_width / 100.0;
    //0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double middle_d2 = d2_v_middle;
    //result[0]{0};
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    //
    //delay(5);	//to settle at this value
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

// Initialisation of FPU, block with only V-MSA in use
// It is only for warm context !
block Init_MSA_V_fm_warm HIFI 3218 {
    string band = "1a";
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
}{
    Start_block();
    {double,string}[] result_d = ConfigurationReaderWarm("name_confilfpu",["band"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],"0",0.0);
    //
    double volt_H_FIF_1 = result_d[0]{0};
    double curr_H_FIF_1 = result_d[1]{0};
    double volt_H_FIF_2 = result_d[2]{0};
    double curr_H_FIF_2 = result_d[3]{0};
    //
    double volt_H_SIF_1 = result_d[4]{0};
    double curr_H_SIF_1 = result_d[5]{0};
    double volt_H_SIF_2 = result_d[6]{0};
    double curr_H_SIF_2 = result_d[7]{0};
    double volt_H_SIF_3 = result_d[8]{0};
    double curr_H_SIF_3 = result_d[9]{0};
    // 
    result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReaderWarm("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    //Get biases
    result_d = ConfigurationReaderWarm("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReaderWarm("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReaderWarm("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode","diplexer_current_normal_h","diplexer_current_normal_v"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        //double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_d[2]{0};
        //result_dip[0];
        diplex_V = result_d[3]{0};
        //result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReaderWarm("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    Hifi_HIFI_non_periodic_hk_FCU();
}

/////////////////////////////////////////////////////////////////
// Auxiliary routine to determine the two loop phase durations  and
// the OFF resolution for all FSwitch modes
{double,double,double,double} procedure FSwitchPhaseLengths {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
}{
    // limits from noise section
    // resolution of OFF phase
    double sw_resolution = GetFSwitchSWResolution(band,lo_freq);
    sw_resolution = max(effResolution{1},sw_resolution);
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    double allan_time_off = allanparms[0] * pow(1.0 / sw_resolution,binningexp);
    // Differential Allan variance
    allanparms = InterpolateSpecFSwitchAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double dalpha = allanparms[1];
    binningexp = 1.0 / allanparms[2];
    double dallan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // phase lengths
    double main_phase = 0.3 * dallan_time_lores;
    double chop_phase = 0.3 * allan_time_lores;
    double chop_phase_off = 0.3 * allan_time_off;
    // Constrain by load period
    int loadper = LoadPeriod(band,lo_freq,effResolution{0});
    main_phase = min(main_phase,0.4 * double(loadper));

    return {main_phase,chop_phase,chop_phase_off,sw_resolution};
}

// Detector heater control: COP version does not switch magnet back to normal at end
block Heater_cop HIFI 3940 {
    string band = "1a";
}{
    //Get name of FPU configuration file
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["normal_heater_time_h","normal_heater_time_v","heater_delay_h","heater_delay_v","magnet_current_max_h","magnet_current_max_v"],band,0.0);
    double normal_heater_time_h = result_d[0]{0};
    double normal_heater_time_v = result_d[1]{0};
    int heater_delay_h = iround(result_d[2]{0});
    int heater_delay_v = iround(result_d[3]{0});
    //Magnets need to be switched to 0 prior to the deflux
    Hifi_HIFI_CH1_MX_MG_C($BBID,0.0);
    Hifi_HIFI_CV1_MX_MG_C($BBID,0.0);
    delay(1);
    //
    Hifi_HIFI_HF_CH1_DHTR_C($BBID,normal_heater_time_h);
    delay(iceil(normal_heater_time_h / 1000.0) + 1);
    //
    int startobs = time();
    //Extra delay for cooling down temperature: will be included in the V-mixer delay
    //delay(heater_delay_h);
    Hifi_HIFI_HF_CV1_DHTR_C($BBID,normal_heater_time_v);
    delay(iceil(normal_heater_time_v / 1000.0) + 1);
    //Extra delay for cooling down temperature: both mixers cool down together
    delay(heater_delay_v);
    //
}

//Set data rate - used after boot command
block HKrate_block_ops HIFI 7924 {
    double rate = 0.2;
}{
    StartBlock_ops();
    string hk_rate = "1_pkt_per_10_s";
    if(rate < 0.2) {
        hk_rate = "1_pkt_per_10_s";
    }
    if(rate >= 0.2 && rate < 0.25) {
        hk_rate = "1_pkt_per_5_s";
    }
    if(rate >= 0.25 && rate < 0.33) {
        hk_rate = "1_pkt_per_4_s";
    }
    if(rate >= 0.33 && rate < 1.0) {
        hk_rate = "1_pkt_per_3_s";
    }
    if(rate >= 1.0) {
        hk_rate = "1_pkt_per_s";
    }
    Hifi_HIFI_Housekeeping_on(hk_rate,"ON","ON","ON","ON","ON","ON");
    mois_tmcheck("Verify that HIFI telemetry packets (3,25,1025) - HIFI_PERIODIC_HK - are arriving at a " + hk_rate + " rate.");
    delay(1);
}

//Procedure checking the consistency of slow chop spectroscopy
//parameters to be sent to configuration command.
bool procedure Check_fast_chop_parameters_proc {
    int n_wbs_start = 1; //Nb of loops
    int r_hrs = 1; //Nb of HRS readout per WBS readout
    int n_wbs_integr = 4; //Number of wbs readout packetized per WBS frame
    int n_hrs_integr = 4; //Number of hrs readout packetized per HRS frame
    int del_hrs = 5; //Delay before starting HRS integration
    int del_wbs = 5; //Delay before starting WBS integration
    int t_acc_wbs = 1005; //Duration of WBS frame: it sets the chopping rate
    int t_acc_hrs = 950; //Duration of HRS frame
    int wbsh_offset1 = 0;
    int wbsh_width1 = 2048;
    int wbsh_offset2 = 2048;
    int wbsh_width2 = 2048;
    int wbsh_offset3 = 4096;
    int wbsh_width3 = 2048;
    int wbsh_offset4 = 6144;
    int wbsh_width4 = 2048;
    int wbsv_offset1 = 0;
    int wbsv_width1 = 2048;
    int wbsv_offset2 = 2048;
    int wbsv_width2 = 2048;
    int wbsv_offset3 = 4096;
    int wbsv_width3 = 2048;
    int wbsv_offset4 = 6144;
    int wbsv_width4 = 2048;
    int hrs_rshift = 0; //HRS bit shift
    int wbs_rshift = 0; //WBS bit shift
    int hrsh_sel = 255; //HRS-H band selection
    int hrsv_sel = 255; //HRS-V band selection
    string wbs_packing = "24_bits_format";
    int n_wbs_1 = 8; //n_wbs_1: number of WBS cycles (should be even)
    int n_hrs_trans = 1; //n_hrs_trans: HRS loop when transferring WBS packets
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    error("Procedure Check_fast_chop_parameters_proc is not used anymore.");

    return false;
}

//HIFI-COP-1.2-WBS_FT
obs HifiEng_WBS_FT_COP {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(WBS_FT_COP_proc_ops(prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            WBS_FT_COP_proc_ops(prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

{string,double,double}[] procedure HifiSScanModeDBSSequencerInit {
    string modeName = "freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hr1{0},hr1{1},hr1{3}},{hr2{0},hr2{1},hr2{3}},wb1,wb2};
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    // Now general part of DBS modes
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // Get the drift parameters to compute the drift noise
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {double,double} phaselengths = DBSPhaseLengths(band,reffreq,effResolution,continuumDetection,narrowReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // remaining part for n_switch
    int n_switch_on_guess = iceil(phaselengths{0}) / (n_freq_point_guess * 2 * data_time_guess) + 1;
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)}];

    return retvalues;
}

// Spectrometer configuration for total power, procedure
// Uses the efficient AOT assumptions, but also their scos_jitter
int[] procedure Configure_Spectrometer_AOTlike_proc_fm {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5,wb6,wb7,wb8
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Compute data_time and n_switch use the wrapper
    int[] res = ConfigSlowChop(integ_time,"tp",band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_switch = res[1];
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS. 
    // The deadtimes output is not used at ILT level.
    {double,double} dtimes = ConfigSpectroscopySlowChop(data_time,n_switch,"tp",band,0.0,backendreadoutparms,true);
    //
    //Necessary for call in Dip_FSW_COP_proc_ops
    Hifi_HIFI_noop();

    return res;
}

//  LCU configuration into NOMINAL mode, procedure
procedure LCU_config_nominal_proc_aot {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; //LO frequency
}{
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //Fetch best guess, and clip to blue max
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    drain2_v = min(result[0]{0},drain2_bluemax);
    //Send command: expect that we have already switched to NOMINAL
    //We set D2 to best guess and wait some time to stabilize chain temperature
    HIFI_Configure_LCU_block_aot(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,config_lo_delay);
    //
    //TM page dump and error flag clearance now contained in the above block
}

/////////////////////////////////////////////////////////////////
// Fast-chop spectral scan observing modes
// 
// Combination of four modules implementing the new structure 
//
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiSScanProcFastDBS {
    /* Setup parameters */
    int naifid = 0; // Tracing object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - DBS fastChop",{data_time,0,n_switch_on,n_int_on,0,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time / 2);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,int,int,int,bool,int,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = FastSScanDBS_pre_timing(band,lo_freq,lo_freq_up,redundancy,effResolution,hr1,hr2,wb1,wb2,data_time,n_int_on,n_switch_on,n_freq_point,n_cycles,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    int n_total = groupnumber * n_cycles;
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = DBS_telescope(naifid,onPosition,band,reffreq,"",pre_timing{0},n_total);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},double,double,double} post_timing = SScanDBS_post_timing(pre_timing{0},telescopetimes,n_freq_point,groupnumber,n_cycles,true);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,reffreq,"",post_timing{1},n_total);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    // normal pre_timing values
    int n_loadinterval = post_timing{1}{7};
    int n_bchop = post_timing{1}{8};
    int shiftlength = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    double avnumchop = post_timing{2};
    // efficiency parameters
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FastSScanDBS_commanding(band,reffreq,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,n_int_on,n_cycles,n_total,n_bchop,n_switch_on,n_loadinterval,startobs,telescopetimes,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastSScanDBS_deadtimes(band,reffreq,hr1,hr2,wb1,wb2,n_freq_point,data_time,n_int_on,n_bchop,n_switch_on,n_cycles,avnumchop,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanDBS_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,continuumDetection,n_cycles,tscan,tact);
    // Evaluate performance
    SScanDBS_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_total,groupnumber * n_freq_point,avnumchop * double(n_int_on),tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// HRS attenuator tuning, block
// Both polarizations are treated
block HRS_tune_block_fm HIFI 3601 {
    string band = "1a"; // HIFI band
}{
    //Start_block(); 
    //Now tune attenuators: it sets the HRS to ultra_wide
    Hifi_HIFI_Tune_HRS($BBID);
    //Get delay
    {double,string}[] result_d = ConfigurationReader("name_delays",["hrs_tune_delay"],band,0.0);
    int hrs_tune_delay = iround(result_d[0]{0});
    delay(hrs_tune_delay);
    //
}

// Stability test, procedure, case 4
// Measurement of internal cold against external hot
procedure Proc_stability_intcold_exthot {
    string band = "1a"; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total (co-added) integration time of a phase in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "slowchop" in ["slowchop","fastchop"]; //Whether to use slowchop or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    //
    Chopper_Rotation_block_fm(band,"chop_hot_ang","chop_M3_ang");
    //Look at external HBB
    //Open shutter
    //Shutter_rotate_proc_fm("open");
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        //Configure and tune backends
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration after tuning: done later
    //Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    Stability_intcold_exthot_fm(band,n,integ_time,hrs_mode,backend,chopmode,chop_phase);
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
    //2 sec. integration
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of OTF observing mode
{int,int,int,int,int,int,int,int} procedure OTFmap_pre_timing {
    int nlines_tot = 1; // Number of rows in the map
    int npoints = 10; // Number of data dumps per row
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,5]; // chunk size given by the data rates and optimum speed
    int n_supersample = 1 in [1,1800]; // Supersamplingfactor
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_intoff = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    // Is the map size an integer multiple of the scan size?
    if(nlines_tot == 1) {
        int n_scans = 1;
    } else {
        if(nlines_tot % n_linesperscan != 0) {
            SError("Map size is no integer multiple of the scan size.");
        }
        n_scans = nlines_tot / n_linesperscan;
    }
    // Compute parameters for the instrument timing
    CheckReasonableLineNumber(nlines_tot,true);
    int n_pp = npoints * n_supersample;
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Compute parameters for the pointing command
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    int off_inttime = n_intoff * data_time;
    // OFF integration time
    int off_pointing = off_inttime + jitterdead;
    // increase by commanding jitter
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,false);
    }
    initlength = initlength + loadlength;
    // First estimate of the load interval
    int scan_time = n_linesperscan * n_pp * data_time + off_pointing;
    if(scan_time > load_interval) {
        IError("Scan duration too long for required load period. " + "Reduce the map size or increase the step size.");
    }
    int n_loadinterval = imax(load_interval / scan_time,1);
    n_loadinterval = imin(n_loadinterval,32);
    // Make sure that load slews occur at the same position in each coverage
    n_loadinterval = IMultiple(n_loadinterval,n_scans);
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed in the observing mode modules

    return {n_pp,n_scans,off_inttime,off_pointing,loadlength,n_loadinterval,initlength,dangling};
}

//PDU switch on of a S/S, procedure
procedure PDU_switch_on_proc_ops {
    string subsystem = "ICU_Prime" in ["ICU_Prime","ICU_Red","LO_Prime","LO_Red","WBS_H","WBS_V","HRS_H","HRS_V"];
}{
    ////HifiIltEgse_PDU_switch_on($BBID,subsystem);	//The TEI command:  WILL BE DONE BY SPACON
    mois_spacon("Please power ON Sub-System " + subsystem);
    if(subsystem == "ICU_Prime" || subsystem == "ICU_Red") {
        mois_tmcheck("Verify PDU current for HIFI ICU is 1.0A +/- 10%");
        mois_tmcheck("Verify arrival of (5,1) telemetry packet from HIFI after 10sec. (5,1) packets should then arrive every 10sec.");
        if(subsystem == "ICU_Prime") {
            mois_tmcheck("If the (5,1) telemetry packet is not received, HIFI is in RESCUE mode and the following procedures shall be executed: HIFI_Rescue_to_SwitchedOff_Prime, then HIFI_SwitchedOff_to_Intermediate_Redundant if this has not yet been attempted. Please contact the HIFI ICC in any case.");
            mois_tmcheck("If a (5,4) telemetry packet has been received, HIFI is in RESCUE mode and the following procedure shall be executed: HIFI_Rescue_to_SwitchedOff_Prime. Please contact the HIFI ICC.");
        }
        if(subsystem == "ICU_Redundant") {
            mois_tmcheck("If the (5,1) telemetry packet is not received, HIFI is in RESCUE mode and the following procedure shall be executed: HIFI_Rescue_to_SwitchedOff_Redundant, then HIFI_SwitchedOff_to_Intermediate_Prime if this has not yet been attempted. Please contact the HIFI ICC in any case.");
            mois_tmcheck("If a (5,4) telemetry packet has been received, HIFI is in RESCUE mode and the following procedure shall be executed: HIFI_Rescue_to_SwitchedOff_Redundant. Please contact the HIFI ICC.");
        }
    }
    //Check current for other S/S
    if(subsystem == "LO_Prime" || subsystem == "LO_Red") {
        mois_tmcheck("Verify PDU current for HIFI LCU is 0.9A +/- 0.25A");
    }
    if(subsystem == "WBS_H") {
        mois_tmcheck("Verify PDU current for HIFI WBS-H is 0.92A +/- 10%");
    }
    if(subsystem == "WBS_V") {
        mois_tmcheck("Verify PDU current for HIFI WBS-V is 0.92A +/- 10%");
    }
    if(subsystem == "HRS_H") {
        mois_tmcheck("Verify PDU current for HIFI HRS-H is 2.32A +/- 10%");
    }
    if(subsystem == "HRS_V") {
        mois_tmcheck("Verify PDU current for HIFI HRS-V is 2.32A +/- 10%");
    }
    //delay(1);
}

//General LO configuration command
procedure HIFI_Configure_LCU_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    int freq_nx = 0; // HL_freq_nx
    int lsu_main = 0; // HL_LSU_main
    int lsu_offset = 0; // HL_LSU_offset
    int d2_step = 1; // HL_D2_step
    double plevel_v = 0.0;
    double m1_v = 9.0;
    double m2_v = -2.0;
    double m3_v = 0.0;
    double gate1_v = -2.5;
    double gate2_v = -2.5;
    double drain1_v = 2.8;
    string curlim1_v = "1.4";
    double drain2_v = 2.6;
    string curlim2_v = "1.4";
    int macro_checksum = 0; // HL_macro_checksum
    int config_lo_delay = 6;
}{
    //Check that Vd2 is within the blue limits
    drain2_v = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v);
    //
    //
    //Execute configuration
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_safe_LCU_ch1a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_safe_LCU_ch1b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_safe_LCU_ch2a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_safe_LCU_ch2b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_safe_LCU_ch3a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_safe_LCU_ch4a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_safe_LCU_ch4b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
    delay(config_lo_delay);
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//Set LCU4a back to standby status, procedure
procedure LCU4a_standby_proc_fm {
    string band = "4a"; // HIFI band
    double lo_freq = 1000.0 in [967.0,1042.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

// Standing wave analysis
// Retune case for band 2a
//HIFI-COP-3-StWv1
procedure Standing_wave_retune_COP_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    int freq_index = 1; //The frequency index to consider: 1 to 4
    string los_code = "sc" in ["sc","sh","ss"]; //The line-of-sight code: sc (sky-CBB), sh (sky-HBB), ss (sky-sky)
}{
    //Retrieve frequencies from LUT
    string tabstwv = "config_stwvfreq.config";
    double bandnb = GetBandCode(band);
    //
    //Check consistency of request
    if(freq_index > 1 && (los_code == "sh" || los_code == "ss")) {
        error("You cannot select this line-of-sight with this frequency index");
    }
    if(iround(bandnb) % 2 == 0 && (los_code == "sh" || los_code == "ss")) {
        error("You cannot select this line-of-sight with b-bands");
    }
    //Fetch observing parameters
    double lo_freq = dlookup(tabstwv,"" + iceil(bandnb),"freq" + freq_index);
    int integ_time = ilookup(tabstwv,"" + iceil(bandnb),"t" + freq_index);
    int total_stepnb = ilookup(tabstwv,"" + iceil(bandnb),"n" + freq_index + "_" + los_code);
    //
    if(lo_freq == 0.0) {
        error("There is no frequency associated with this band and this frequency index");
    }
    //
    HRS_config_block_fm(band,hrs_mode);
    //
    int[] res = [0,0];
    if(los_code == "sh") {
        res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    } else {
        res = Configure_Spectrometer_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    }
    int total_time = res[0] * res[1];
    //
    double step = 0.015;
    //GHz
    double stepnb = double(total_stepnb / 2);
    double[] lo_freq_input = [0.0,0.0,0.0];
    //Build lo_freq_input array
    lo_freq_input = [lo_freq - stepnb * step,lo_freq + stepnb * step,step];
    int nb_retune = 1;
    Standing_wave_retune_fm_COP(band,total_time,hrs_mode,backend,lo_freq_input,los_code,nb_retune);
    //
}

// Spectrometer configuration for frequency switch, low level procedure
int[] procedure Configure_Spectrometer_freq_switching_proc_fm {
    string band = "1a"; // HIFI band
    int integ_time = 8; //Total integration time in sec. for the two phases !
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Compute data_time and n_switch use the wrapper
    int[] res = ConfigSlowChop(integ_time,"fs",band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_switch = res[1];
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS.
    // The deadtimes output is not used at ILT level.
    {double,double} dtimes = ConfigSpectroscopySlowChop_IST(data_time,n_switch,"fs",band,0.0,backendreadoutparms,true);
    //

    return res;
}

// Procedure to get the instrument boresight string for the used band
string procedure GetBoresight {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    bool chopped = false; // left chopper or center chopper position
}{
    // Get major number
    double[] x = CalibrationReader("beam",["beamnumber"],band,lo_freq);
    int major = iround(x[0]);
    // Polarization is not used any more - only synthesized beam
    int bestWbs = 0;
    // Construct minor number
    // Frequency: this is coded in the next digit of the beamnumber
    if(iround(x[0] * 10.0 % 10.0) > 0) {
        int freqbeam = 1;
    } else {
        freqbeam = 0;
    }
    // chop angle
    if(chopped) {
        int chopbeam = 1;
    } else {
        chopbeam = 0;
    }
    int minor = bestWbs + 2 * freqbeam + 4 * chopbeam + 1;
    // Construct finally the boresight string
    string boresight = "H" + major + minor + "_0";

    return boresight;
}

// Procedure to compute all parameters needed in a Configure_spectroscopy
{int,int,int,int,int,int,int,int,int,int,int,int,int} procedure FastConfigureSpectroscopyParams_IST {
    /* Integration time */
    int data_time = 10 in [4,128]; // data dump interval
    int n_int = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    /* Backend settings */
    bool wbs_used = true; // whether at least one WBS is used
}{
    // Get fixed parameters from configuration and calibration files
    // WBS delta time given by switch dead time
    double res = GetSkyChopDeadTime(band,lo_freq);
    int del_wbs = iceil(res * 1000.0);
    // Additional delays in the readout loops - given in OBS user manual
    {double,string}[] result = ConfigurationReader("name_delays",["add_hrs","add_wbs","add_jitter","wbs_readout","wbs_chunksize","tacc_add","max_hrs_phase","wbs_init"],band,lo_freq);
    int add_hrs = iround(result[0]{0});
    int add_wbs = iround(result[1]{0});
    int add_jitter = iround(result[2]{0});
    int wbs_readout = iround(result[3]{0});
    int wbs_chunksize = iround(result[4]{0});
    int tacc_add = iround(result[5]{0});
    int max_hrs_phase = iround(result[6]{0});
    int wbs_init = iround(result[7]{0});
    // In fast chop del_hrs can be zero, but see SCR 854
    int del_hrs = add_jitter;
    // WBS
    // Fixed parameter - we never split a transfer
    int n_wbs_integr = 1;
    int n_wbs1 = 2 * n_int;
    int n_wbs_start = n_data;
    // HRS is integrated up as long as the WBS
    int n_hrs_integr = n_int;
    // Split data_time into chop phases
    // Dead time per read out (not clear whether add_wbs applies here)
    int tdead_data = 2 * (wbs_readout + add_jitter) + add_wbs - add_jitter;
    // Initial dead time - distribute over all readouts
    int tdead_init = (wbs_init + n_data - 1) / n_data;
    int chop_phase = (1000 * data_time - tdead_data - tdead_init) / (2 * n_int);
    // dead time has to be an integer multiple of the 10ms chunk time
    int tdead_chop = del_wbs + add_jitter;
    int nchunk = (tdead_chop - 1) / wbs_chunksize + 1;
    int tcorr = nchunk * wbs_chunksize - tdead_chop;
    del_wbs = del_wbs + tcorr;
    tdead_chop = tdead_chop + tcorr;
    // Accumulation time
    int t_acc_wbs = chop_phase - tdead_chop;
    // discretize in 10ms chunks
    nchunk = (t_acc_wbs - tacc_add) / wbs_chunksize;
    t_acc_wbs = nchunk * wbs_chunksize + tacc_add;
    // HRS
    // Fixed parameter here
    int r_hrs = 1;
    int t_acc_hrs = t_acc_wbs - add_jitter - del_hrs - add_hrs;
    if(t_acc_hrs > max_hrs_phase) {
        SError("Chop phase length too long for HRS. Increase chop frequency.");
    }
    // How many HRS integrations possible during WBS readout
    int t_hrs_per = t_acc_hrs + del_wbs + add_hrs;
    int n_hrs_trans = wbs_readout / t_hrs_per;
    // This currently does not work - SCR 854: skipped
    n_hrs_trans = 0;
    // Actual integration time and dead time per readout
    // If WBS is used count only the WBS time
    if(wbs_used) {
        tdead_chop = tdead_chop + tacc_add;
        int tint_act = nchunk * wbs_chunksize * n_wbs1 * n_data;
    } else {
        tdead_chop = tdead_chop + r_hrs * add_hrs;
        tdead_data = tdead_data + add_jitter - 2 * (n_hrs_trans * t_hrs_per - add_jitter);
        tint_act = t_acc_hrs * r_hrs * (n_wbs1 + 2 * n_hrs_trans) * n_data;
    }
    // Return all config_spectroscopy timing parameters

    return {n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,n_wbs1,n_hrs_trans,tdead_chop,tdead_data,tint_act};
}

//TM to control heater values of LOU, procedure
procedure HL_heater_proc_ops {
    string band = "1a" in ["ALL","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band. ALL does all bands and all multipliers
    string context = "nominal" in ["nominal","stby"]; //whether heater applies to stby or nominal context
}{
    mois_step("Switch on LO heater for standby");
    double[] cresult = CalibrationReader("name_loheater",["heater_nominal","heater_stby"],band,0.0);
    double hifi_HL_heater = cresult[0];
    if(context == "stby") {
        hifi_HL_heater = cresult[1];
    }
    Hifi_HIFI_HL_heater($BBID,hifi_HL_heater);
    delay(1);
    mois_spacon("Check that parameter HL_Eheater is set to " + hifi_HL_heater);
}

// LO SFT, following procedure of MPI, procedure
//  Uses SFT approach with old 5 TM TC call
procedure LO_SFT_proc_sft {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //
    double lo_freq = 0.0;
    double drain2_v = 0.0;
    double[] cresult_d = CalibrationReader("name_keyfreq",["keyfreq","key_d2v_P","key_d2v_R"],band,0.0);
    lo_freq = cresult_d[0];
    //applies to cold LO
    //Switch on with safe Vd2
    LCU_switchon_proc_sft(band);
    //LO freq and Vd2 to use is embedded in the proc
    //Wait total of 20 sec.
    delay(20);
    //Check what d2_v to use depending on test circumstances
    drain2_v = cresult_d[1];
    //Value for prime case, and fm H/W
    //
    if(prime_or_redundant == "Red") {
        drain2_v = cresult_d[2];
    }
    //
    LCU_config_nominal_w_D2_proc_sft(band,lo_freq,drain2_v);
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double} procedure FastSScanDBS_deadtimes {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int grouplen = 1; // Number of frequency steps per nodding phase
    int data_time = 4; // chunk size
    int n_int = 20; // Number of integrations in one readout cycle
    int n_bchop = 1; // Normal number of chop cycles per frequency and pointing
    int n_long = 1; // Chop cycles per frequency and pointing without retuning
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    double avnumchop = 1.0; // Average number of chop cycles per frequency
    double tdead = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Compute parameters for the instrument timing in normal phases
    {double,double} tinst = GetInstDeadFastChop(data_time,n_int,n_long,band,lo_freq,backendreadoutparms);
    // dead time
    double tdeadint = double(data_time * n_long) - tinst{0};
    // subtract dead times in switches
    // only half of them are subtracted due to ABAB scheme
    tdeadint = tdeadint - double(n_int * n_long) * tinst{1};
    // treat integration times of other frequencies as dead time
    double tdeadother = double(data_time * 2 * n_long);
    // Store
    double tswitch = tinst{1};
    // Integration time
    double tphaseint = tinst{0};
    // Correcton in case of cycles with shorter integrations
    if(n_cycles > 1) {
        tinst = GetInstDeadFastChop(data_time,n_int,n_bchop,band,lo_freq,backendreadoutparms);
        // dead time
        double tdeadshort = double(data_time * n_bchop) - tinst{0};
        // subtract dead times in switches
        tdeadshort = tdeadshort - double(n_int * n_bchop) * tinst{1};
        // weigh
        tdeadint = (tdeadint * double(n_cycles - 1) + tdeadshort) / double(n_cycles);
        tphaseint = (tphaseint * double(n_cycles - 1) + tinst{0}) / (2.0 * avnumchop * double(n_cycles) * double(n_int));
        tdeadother = (tdeadother * double(n_cycles - 1) + double(data_time * 2 * n_bchop)) / double(n_cycles);
    } else {
        tphaseint = tphaseint / (2.0 * avnumchop * double(n_int));
    }
    // Total dead time per cycle
    double tdead_tot = tdead + double(2 * grouplen) * tdeadint;
    // Add integration times of other frequencies as dead time
    tdead_tot = tdead_tot + double(grouplen - 1) * tdeadother;

    return {tdead_tot,tphaseint,tswitch};
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure SScanLoadChop_commanding {
    string band = "4a"; // HIFI band
    double reffreq = 978300.0; // Reference characteristic LO frequency 
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int grouplen = 1; // Number of frequency steps per nodding phase
    int[][] grouporder = [[0],[0]]; // Sequence to trace frequency points in both phases
    double[] freqgrid = [978053.7,978301.8,978381.1]; // Table of frequency points
    bool retuning = false; // need for WBS retuning
    double[] targetlevels = [1.0,1.0,1.0]; // WBS tuning levels
    int data_time = 4; // chunk size
    int data_time_off = 4; // data dump interval on OFF
    int n_per_on = 1; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int n_per_off = 1; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_long_on = 1; // number of cycles on ON without retuning
    int n_long_off = 1; // number of cycles on OFF without retuning
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int allsteps = 4; // Total number of frequency pointing periods
    int n_loadinterval = 1; // number of nods before a load measurement
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int shiftlength = 0; // Shift of the loop start relative to the pointing
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    // First frequency
    double runningfreq = freqgrid[grouporder[1][0]];
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] onrates = dataparms{1};
    dataparms = DataTaking(backendreadoutparms,data_time_off);
    double[] offrates = dataparms{1};
    int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,reffreq,backendreadoutparms);
    // recompute load duration for initial load measurement
    int loadlength = duration(SScanLoadMeasurement(band,runningfreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms));
    loadlength = loadlength + readoutdead;
    bool retuneload = n_loadinterval > 1;
    // Tuning levels
    string[] targetnames = TargetNames(band,reffreq,retuning,targetlevels);
    string target = targetnames[0];
    // All commands with a duration possibly depending on the frequency
    // are taken at the reference frequency to guarantee synchonization
    // Declare auxiliary variables to be used in the loops
    int i_freqcycles = 0;
    int i_group = 0;
    int i_phase = 0;
    // variables storing the configuration setting
    bool islong = false;
    bool isinvalid = true;
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Instrument Initialization:  The instrument tuning is done as early as
            // possible, the load calibration as late as possible
            //
            HIFIInitObs();
            TuneHIFI(band,runningfreq,hrs1,hrs2,wbs1{0},wbs2{0},target);
            delay(tinitslew - (time() - startobs) - loadlength + shiftlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            SScanLoadMeasurement(band,runningfreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms);
            if(shiftlength > 0) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 7) {
            // The NOD-state represents our OFF position
            // Reset group counter
            i_group = 0;
            runintostate = false;
            // long integrations not possible in last and first PS cycle
            if(n_cycles > 1 && state[2] % n_cycles != state[2] % 2) {
                if(isinvalid || !islong) {
                    HIFIConfigureLoadChopIntegration(data_time_off,n_long_off,band,reffreq,backendreadoutparms);
                    islong = true;
                    isinvalid = false;
                }
                HIFILoadChopOffIntegration(data_time_off,n_long_off,band,reffreq,offrates);
            } else {
                if(isinvalid || islong) {
                    HIFIConfigureLoadChopIntegration(data_time_off,n_per_off,band,reffreq,backendreadoutparms);
                    islong = false;
                    isinvalid = false;
                }
                // No group scanning on OFF
                HIFILoadChopOffIntegration(data_time_off,n_per_off,band,reffreq,offrates);
                // Now we switch to the next frequency group or repeat the cycle
                if(state[2] % n_cycles == 0 && state[2] % 2 == 0) {
                    // Big tuning step, but not at end of observation
                    if(state[2] < allsteps) {
                        i_freqcycles = i_freqcycles + 1;
                        runningfreq = freqgrid[grouporder[1][0] + i_freqcycles * grouplen];
                        target = targetnames[i_freqcycles];
                        HIFIRetuneFreq(band,runningfreq,target);
                        runintostate = true;
                    } else {
                        // final load measurement if requested
                        if(final_load) {
                            delay(readoutdead);
                            SScanLoadMeasurement(band,runningfreq,reffreq,retuneload,eff_resolution{0},data_time,backendreadoutparms);
                            runintostate = true;
                        }
                    }
                }
            }
            // Active WBS HK if we have a nod slew without calibration
            if(state[2] % 2 == 1) {
                isinvalid = true;
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 3) {
            // The POINT-state represents our source position
            i_phase = state[2] % 2;
            // ON integration
            runintostate = false;
            // long integrations not possible in last and first nod cycle
            if(n_cycles > 1 && state[2] % n_cycles != (state[2] % 2 + 1) % 2) {
                if(isinvalid || !islong) {
                    HIFIConfigureLoadChopIntegration(data_time,n_long_on,band,reffreq,backendreadoutparms);
                    islong = true;
                    isinvalid = false;
                }
                HIFILoadChopOnIntegration(data_time,n_long_on,band,reffreq,onrates);
            } else {
                if(isinvalid || islong) {
                    HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                    islong = false;
                    isinvalid = false;
                }
                HIFILoadChopOnIntegration(data_time,n_per_on,band,reffreq,onrates);
            }
            // Other frequencies
            // Reset group counter
            i_group = 1;
            if(i_group <= grouplen - 1) {
                if(isinvalid || islong) {
                    HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,reffreq,backendreadoutparms);
                    islong = false;
                    isinvalid = false;
                }
            }
            while(i_group <= grouplen - 1) {
                // retune
                runningfreq = freqgrid[grouporder[i_phase][i_group] + i_freqcycles * grouplen];
                HIFIChangeFreq(band,runningfreq);
                HIFILoadChopOnIntegration(data_time,n_per_on,band,reffreq,onrates);
                i_group = i_group + 1;
            }
            // Now we switch to the next frequency group or repeat the cycle
            if(state[2] % n_cycles == 0 && i_phase == 1) {
                // Big tuning step, but not at end of observation
                if(state[2] < allsteps) {
                    i_freqcycles = i_freqcycles + 1;
                    runningfreq = freqgrid[grouporder[0][0] + i_freqcycles * grouplen];
                    target = targetnames[i_freqcycles];
                    HIFIRetuneFreq(band,runningfreq,target);
                    runintostate = true;
                } else {
                    // final load measurement if requested
                    if(final_load) {
                        delay(readoutdead);
                        SScanLoadMeasurement(band,runningfreq,reffreq,retuneload,eff_resolution{0},data_time,backendreadoutparms);
                        runintostate = true;
                    }
                }
            }
            // Active WBS HK if we have a nod slew without calibration
            if(state[2] % 2 == 0) {
                isinvalid = true;
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load switch
            delay(readoutdead);
            SScanLoadMeasurement(band,runningfreq,reffreq,retuneload,eff_resolution{0},data_time,backendreadoutparms);
            isinvalid = true;
            runintostate = false;
        }
        // Danging load - already covered above
        // otherwise the instrument stops halftunelength before the telescope
        if(state[0] == 5) {
            // finished shift of instrument operations relative to pointing command
            runintostate = false;
            HIFICloseObs();
        }
    }
}

// Initialisation of FPU, block with only H-MSA in use
// It is only for warm context !
block Init_MSA_H_fm_warm HIFI 3217 {
    string band = "1a";
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReaderWarm("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],"0",0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReaderWarm("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    //Get biases
    result_d = ConfigurationReaderWarm("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReaderWarm("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReaderWarm("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode","diplexer_current_normal_h","diplexer_current_normal_v"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        //double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_d[2]{0};
        //result_dip[0];
        diplex_V = result_d[3]{0};
        //result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReaderWarm("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    Hifi_HIFI_non_periodic_hk_FCU();
}

//PDU switch on of a S/S, block
block PDU_switch_on_block_ops HIFI 7657 {
    string subsystem = "ICU_Prime" in ["ICU_Prime","ICU_Red","LO_Prime","LO_Red","WBS_H","WBS_V","HRS_H","HRS_V"];
}{
    if(subsystem != "ICU_Prime" && subsystem != "ICU_Red") {
        StartBlock_ops();
        //This has no delay 
    }
    ////HifiIltEgse_PDU_switch_on($BBID,subsystem);	//The TEI command: WILL BE DONE BY SPACON
    mois_spacon("Please power ON Sub-System " + subsystem);
    if(subsystem == "ICU_Prime" || subsystem == "ICU_Red") {
        mois_tmcheck("Verify PDU current for HIFI ICU is 1.0A +/- 10%");
        mois_tmcheck("Verify arrival of (5,1) telemetry packet from HIFI after 10sec. (5,1) packets should then arrive every 10sec.");
        if(subsystem == "ICU_Prime") {
            mois_tmcheck("If the (5,1) telemetry packet is not received, HIFI is in RESCUE mode and the following procedures shall be executed: HIFI_Rescue_to_SwitchedOff_Prime, then HIFI_SwitchedOff_to_Intermediate_Redundant if this has not yet been attempted. Please contact the HIFI ICC in any case.");
            mois_tmcheck("If a (5,4) telemetry packet has been received, HIFI is in RESCUE mode and the following procedure shall be executed: HIFI_Rescue_to_SwitchedOff_Prime. Please contact the HIFI ICC.");
        }
        if(subsystem == "ICU_Redundant") {
            mois_tmcheck("If the (5,1) telemetry packet is not received, HIFI is in RESCUE mode and the following procedure shall be executed: HIFI_Rescue_to_SwitchedOff_Redundant, then HIFI_SwitchedOff_to_Intermediate_Prime if this has not yet been attempted. Please contact the HIFI ICC in any case.");
            mois_tmcheck("If a (5,4) telemetry packet has been received, HIFI is in RESCUE mode and the following procedure shall be executed: HIFI_Rescue_to_SwitchedOff_Redundant. Please contact the HIFI ICC.");
        }
        //
    }
    //Check current for other S/S
    if(subsystem == "LO_Prime" || subsystem == "LO_Red") {
        mois_tmcheck("Verify PDU current for HIFI LCU is 0.9A +/- 0.25A");
    }
    if(subsystem == "WBS_H") {
        mois_tmcheck("Verify PDU current for HIFI WBS-H is 0.92A +/- 10%");
    }
    if(subsystem == "WBS_V") {
        mois_tmcheck("Verify PDU current for HIFI WBS-V is 0.92A +/- 10%");
    }
    if(subsystem == "HRS_H") {
        mois_tmcheck("Verify PDU current for HIFI HRS-H is 2.32A +/- 10%");
    }
    if(subsystem == "HRS_V") {
        mois_tmcheck("Verify PDU current for HIFI HRS-V is 2.32A +/- 10%");
    }
    //delay(1);
}

// HRS partial configuration, block
// Configures the resolution mode
block HRS_config_resol_block_fm HIFI 3618 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    //Start_block();
    ////////////////////////////////////////////////////////////////////
    //Now Configure blocks
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_block_1","hrh_block_2","hrh_block_3","hrh_block_4","hrh_block_5","hrh_block_6","hrh_block_7","hrh_block_8"],band,0.0);
    string hrh_block_1 = result[0]{1};
    string hrh_block_2 = result[1]{1};
    string hrh_block_3 = result[2]{1};
    string hrh_block_4 = result[3]{1};
    string hrh_block_5 = result[4]{1};
    string hrh_block_6 = result[5]{1};
    string hrh_block_7 = result[6]{1};
    string hrh_block_8 = result[7]{1};
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrh_block_1,hrh_block_2,hrh_block_3,hrh_block_4,hrh_block_5,hrh_block_6,hrh_block_7,hrh_block_8);
    //delay(hrs_config_delay);
    //
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_block_1","hrv_block_2","hrv_block_3","hrv_block_4","hrv_block_5","hrv_block_6","hrv_block_7","hrv_block_8"],band,0.0);
    string hrv_block_1 = result[0]{1};
    string hrv_block_2 = result[1]{1};
    string hrv_block_3 = result[2]{1};
    string hrv_block_4 = result[3]{1};
    string hrv_block_5 = result[4]{1};
    string hrv_block_6 = result[5]{1};
    string hrv_block_7 = result[6]{1};
    string hrv_block_8 = result[7]{1};
    //
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrv_block_1,hrv_block_2,hrv_block_3,hrv_block_4,hrv_block_5,hrv_block_6,hrv_block_7,hrv_block_8);
    //
    //Wait delay to allow all setting to be configured
    delay(hrs_config_delay);
}

// Configuration for load-chop integration
block HIFIConfigureLoadChopIntegration HIFI 6034 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used, channel windows}
}{
    // Call procedure doing the work
    ConfigureSpectroscopy(data_time,2 * n_cycle,"lchop",band,lo_freq,backendreadoutparms);
}

// WBS laser temperature control switched on, block
block Laser_T_check_on_fm HIFI 3704 {
    double laserT_limit = 40.0; //new limit above which OBS switches off the laser
}{
    int nbreach = 5;
    Hifi_HIFI_WH_Laser_T_check_on(nbreach,laserT_limit);
    Hifi_HIFI_WV_Laser_T_check_on(nbreach,laserT_limit);
    delay(1);
}

//HIFI-COP-1.2-IF_FT
obs HifiEng_IF_FT_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(IF_FT_COP_proc_ops(band,lo_freq,prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            IF_FT_COP_proc_ops(band,lo_freq,prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

//////////////////////////////////////////////////////
// Definitions to test peakup functions
//
// DT - 20-03-07
//////////////////////////////////////////////////////
// Reminder information:
// peak positions are labelled as follows:
//	i dimension is along chopper rotation
//	j dimension is along M3 long axis
//	(i,j)  -1	0	1
//	1	3	6	9
//	0	2	5	8
//     -1	1	4	7
//////////////////////////////////////////////////////
//modes: see fm_testmodes.cus
//////////////////////////////
// Procedures and blocks
//////////////////////////////
// Simulating PU report packet emission
block Simulate_PU_block_fm HIFI 3822 {
    int hifi_HI_microrot_y = 5; // HI_microrot_y
    int hifi_HI_microrot_z = 7; // HI_microrot_z
}{
    Start_block();
    Hifi_HIFI_simulate_peakup(hifi_HI_microrot_y,hifi_HI_microrot_z);
    delay(1);
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double,double,double} procedure OTFDoubleChop_deadtimes {
    string chopmode = "chop" in ["chop","lchop","fs"]; // chop mode
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int data_time_off = 4; // data dump interval on OFF
    int n_switch_on = 1; // Supersamplingfactor
    int n_switch_off = 3; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_pp = 10; // Number of data dumps per line
    double tdead = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Dead time in OFF
    {double,double} tinst = GetInstDeadSlowChop(data_time_off,2 * n_switch_off,chopmode,band,lo_freq,backendreadoutparms);
    // dead time within OFF
    double tdeadint = double(data_time_off * 2 * n_switch_off) - tinst{0};
    // subtract dead times in switches
    tdeadint = tdeadint - double(n_switch_off) * tinst{1};
    // add to total dead time
    double tdead_tot = tdead + tdeadint;
    double tswitch_off = tinst{1};
    double tphaseint_off = tinst{0} / double(2 * n_switch_off);
    // Dead time in one line
    tinst = GetInstDeadSlowChop(data_time,n_pp,chopmode,band,lo_freq,backendreadoutparms);
    // Dead time for each line
    tdeadint = double(data_time * n_pp) - tinst{0};
    tdead_tot = tdead_tot + double(n_linesperscan) * tdeadint;
    double tswitch_on = tinst{1};
    double tphaseint_on = tinst{0} / double(n_pp);
    // Return total dead time and actual integration times

    return {tdead_tot,tphaseint_on,tphaseint_off,tswitch_on,tswitch_off};
}

//Procedure checking whether the requested integration
//time is compliant with the allowed packet/datarate
//in slow chop spectroscopy context
bool procedure Check_Slow_Chop_datarate {
    int n_wbs_start = 2; //Nb of frames
    int r_hrs = 1; //Nb of HRS readout per WBS readout
    int n_wbs_integr = 1; //Number of wbs readout packetized per WBS frame
    int n_hrs_integr = 1; //Number of hrs readout packetized per HRS frame
    int del_hrs = 5; //Delay before starting HRS integration
    int del_wbs = 5; //Delay before starting WBS integration
    int t_acc_wbs = 4005; //Duration of WBS frame 
    int t_acc_hrs = 1950; //Duration of HRS frame
    int wbsh_offset1 = 0;
    int wbsh_width1 = 2048;
    int wbsh_offset2 = 2048;
    int wbsh_width2 = 2048;
    int wbsh_offset3 = 4096;
    int wbsh_width3 = 2048;
    int wbsh_offset4 = 6144;
    int wbsh_width4 = 2048;
    int wbsv_offset1 = 0;
    int wbsv_width1 = 2048;
    int wbsv_offset2 = 2048;
    int wbsv_width2 = 2048;
    int wbsv_offset3 = 4096;
    int wbsv_width3 = 2048;
    int wbsv_offset4 = 6144;
    int wbsv_width4 = 2048;
    int hrs_rshift = 0; //HRS bit shift
    int wbs_rshift = 0; //WBS bit shift
    int hrsh_sel = 255; //HRS-H band selection
    int hrsv_sel = 255; //HRS-V band selection
    string wbs_packing = "24_bits_format";
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    error("Procedure Check_Slow_Chop_datarate is not used anymore.");

    return false;
}

// Change LO frequency but keep backend configuration - used in spectral scans
//
procedure HIFIRetuneFreq {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency ion MHz
    string level = "sscan_normal"; // Name of target level
}{
    ConfigureFPU(band,lo_freq,false);
    HIFITuneFreq(band,lo_freq,true,level);
}

//Set mixer bias
procedure Mixerbias {
    double bias_h = 0.0;
    double bias_v = 0.0;
}{
    Hifi_HIFI_CH1_MXBIAS_V($BBID,bias_h);
    Hifi_HIFI_CV1_MXBIAS_V($BBID,bias_v);
    delay(1);
}

////////////////////////////////////
// OTF load-chop observing mode without baseline calibration
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcLoadChopOTFNoRef {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints = 10 in [1,720]; // Number of data dumps per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period defines number of lines between two loads
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Mapping - OTF Map Load Chop noRef",{data_time,0,0,n_switch_on,0,0,0,0,n_cycles,load_interval});
    // Auxiliary routine for API parameter correction
    {double,double,int} mapused = ValidMapSize(band,lo_freq,lineDistance,nlines,stepsize,npoints,2 * data_time * n_switch_on);
    double line_used = mapused{0};
    double scanvelocity = mapused{1};
    int npoints_used = mapused{2};
    // Call first part of the timing computer
    {int,int,int,int,bool,int,int} pre_timing = OTFLoadChopNoRef_pre_timing(nlines,npoints_used,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,int} tpar = OTFDoubleChopNoRef_telescope(naifid,onPosition,lineDistance,nlines,line_used,scanvelocity,band,lo_freq,n_cycles,pre_timing);
    // Dummy call to spacecraft command
    int[] telescopetimes = line_scan_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,bool,int,int},double,double} post_timing = OTFDoubleChopNoRef_post_timing(pre_timing,telescopetimes,nlines,data_time,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = OTFDoubleChopNoRef_telescope(naifid,onPosition,lineDistance,nlines,line_used,scanvelocity,band,lo_freq,n_cycles,post_timing{1});
    // Call telescope command
    telescopetimes = line_scan_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{0};
    bool end_load_on = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{2};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        OTFLoadChopNoRef_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,npoints_used * n_switch_on,n_loadinterval,nlines * n_cycles,end_load_on,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SingleChop_deadtimes("fs",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,npoints_used * n_switch_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = PositionSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_switch_on * n_cycles,tscan,tdead);
    // Evaluate performance
    OTFDoubleChopNoRef_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints_used,n_switch_on * n_cycles,false,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//TM to control FDIR on LOU temp
block Set_LO_FDIR_temperatures_block_aot HIFI 6953 {
}{
    // BBID needs to be set manually as the main TC command has no BBID argument
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    //Fetch values to apply: band-independent so far
    double[] cresult = CalibrationReader("name_loheater",["tmin","tmax","nbreach"],"1a",0.0);
    double tmin = cresult[0];
    //Min threshold
    double tmax = cresult[1];
    //Max threshold
    int nbreach = iround(cresult[2]);
    //Number of breach
    //
    Hifi_HIFI_LOU_T_check_on(nbreach,tmax,tmin);
    delay(1);
    //
}

// SFT: Init of all S/S, procedure
// This is only for warm context
procedure HIFI_SFT_proc_warm {
    string band = "1a"; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string mixer_polarization = "H" in ["H","V","B"]; //Polarization: H, V or Both
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string chop_loop = "CLOSE"; //The chopper loop status
    int integ_time = 4; //Total integration time in sec.
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON  
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //
    //Init of instrument: depends on polarization
    //
    if(mixer_polarization == "H") {
        Init_MSA_H_fm_warm(band,chop_loop,lo_freq);
    }
    if(mixer_polarization == "V") {
        Init_MSA_V_fm_warm(band,chop_loop,lo_freq);
    }
    if(mixer_polarization == "B") {
        Init_MSA_fm_warm(band,chop_loop,lo_freq);
    }
    //
    //Configure WBS laser according to user inputs. Delays are included
    //Maximum attenuation is used since it is what is set in the default config file
    //In fact laser should have been switched on previously for the 2 min. stabilization
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_config_w_laser_block_fm(band,laser_H,laser_V);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_config_max_att_block_fm(band,hrs_mode);
    }
    //
    //Init of LO: configuration. Delays are included
    Set_LO_Nominal_block_fm();
    LCU_switchon_proc_fm(band);
    //
    //Configure spectroscopy integration
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
}

//HIFI-COP-2.2-VecscanCal
obs HifiEng_Vecscan_calibration_COP {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Vecscan_calibration_proc_fm_COP(band));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Vecscan_calibration_proc_fm_COP(band);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// WBS bitflip test, block
//  Done for laser1
block FT_WBS_bitflip HIFI 3709 {
    string band = "1a"; // HIFI band
    int n = 100; //number of loops
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //
    //Set zero and comb off
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_OFF");
    delay(2);
    //
    //Initial configuration: overall attenuators set to max., individual attenuators to 0
    //H-Polarization
    //
    {double,string}[] result = ConfigurationReader("name_configwbs",["hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "ON";
    int hwh_heater = iround(result[0]{0});
    string hwh_latchup_s = result[1]{1};
    int hwh_att_band4 = 0;
    int hwh_att_band3 = 0;
    int hwh_att_band2 = 0;
    int hwh_att_band1 = 0;
    int hwh_att_in = 10;
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = "ON";
    string hwv_laser2_s = "OFF";
    int hwv_heater = iround(result[0]{0});
    string hwv_latchup_s = result[1]{1};
    int hwv_att_band4 = 0;
    int hwv_att_band3 = 0;
    int hwv_att_band2 = 0;
    int hwv_att_band1 = 0;
    int hwv_att_in = 10;
    //
    //Loop on overall attenuators
    for(int i = 0 .. n) {
        //========================================
        // Set WBS
        //========
        //0dB attenuation on individual attenuators
        hwh_att_band4 = 0;
        hwh_att_band3 = 0;
        hwh_att_band2 = 0;
        hwh_att_band1 = 0;
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        hwv_att_band4 = 0;
        hwv_att_band3 = 0;
        hwv_att_band2 = 0;
        hwv_att_band1 = 0;
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
        //
        //1dB attenuation on individual attenuators
        hwh_att_band4 = 1;
        hwh_att_band3 = 1;
        hwh_att_band2 = 1;
        hwh_att_band1 = 1;
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        hwv_att_band4 = 1;
        hwv_att_band3 = 1;
        hwv_att_band2 = 1;
        hwv_att_band1 = 1;
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
    }
    //
}

//  LCU configuration into NOMINAL mode, procedure
procedure LCU_config_nominal_w_D2_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    double drain2_v = 1.4; //Drain2 voltage in V
}{
    //Clear potential failure mode
    Set_LO_Nominal_block_fm();
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command: expect that we have already switched to NOMINAL
    //Contrary to QM, the channel is automatically switched ON
    HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,config_lo_delay);
    //
}

//  LCU6La configuration into SAFE mode, procedure
procedure LCU6La_config_safe_proc_fm {
    string band = "6a"; // HIFI band
    double lo_freq = 1500.0 in [1410.0,1575.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure DoubleChop_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int n_cycles = 1; // Number of ON-OFF cycles
    int n_chop_on = 1; // number of half load-sky-sky-load cycles on ON
    int n_chop_off = 1; // number of half load-sky-sky-load cycles on OFF
    bool fs = false; // whether frequency switch used
    double tscan = 60.0; // Total average duration of one scan
    int pointing = 20; // Pointing duration in the source phase  
    {double,double,double,double,double} tact = {10.0,4.9,4.9,0.05,0.05}; // Field of actual dead and integration times
}{
    double inttimeperonphase = tact{1};
    // Actual integration time in ON phase
    double inttimeperoffphase = tact{2};
    // Actual integration time in OFF phase
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    double idealnoise = idealvalues{1} * idealvalues{1};
    double obsnoise = noisevalues{0} * noisevalues{0};
    double efficiency = idealnoise / obsnoise;
    // Compute the actual integration time
    double posinttime = double(n_cycles * 2 * n_chop_on) * inttimeperonphase;
    double posofftime = double(n_cycles * 2 * n_chop_off) * inttimeperoffphase;
    int instrumenttime = iceil(double(n_cycles) * tscan);
    // Check total integration time
    double timeefficiency = (posinttime + posofftime) / double(totaltime);
    // Noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posofftime,timeefficiency,efficiency,relnoise,fs);
}

// Standing wave analysis
// Procedure looping on freq and los to compute total times per band
//HIFI-COP-3-StWv1
procedure Standing_wave_noretune_MOIS_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
}{
    //Retrieve frequencies from LUT
    string tabstwv = "config_stwvfreq.config";
    double bandnb = GetBandCode(band);
    //Include LO switch-on to compute full time: approximative
    if(bandnb < 11.0) {
        delay(1850);
    } else {
        delay(3060);
    }
    //
    int nb_lo_freq = 4;
    string[] los_code = ["sc","sh","ss"];
    int[] res = [0,0];
    double step = 0.015;
    //GHz
    double[] lo_freq_input = [0.0,0.0,0.0];
    //Loop on frequencies
    for(int j = 1 .. nb_lo_freq) {
        double lo_freq = dlookup(tabstwv,"" + iceil(bandnb),"freq" + j);
        int integ_time = ilookup(tabstwv,"" + iceil(bandnb),"t" + j);
        //Loop on line-of-sight
        int nb_los = 3;
        if(j > 1) {
            nb_los = 1;
        }
        for(int i = 0 .. nb_los - 1) {
            if(lo_freq != 0.0) {
                int total_stepnb = ilookup(tabstwv,"" + iceil(bandnb),"n" + j + "_" + los_code[i]);
                double stepnb = double(total_stepnb / 2);
                if(total_stepnb != 0) {
                    HRS_config_block_fm(band,hrs_mode);
                    //
                    if(los_code[i] == "sh") {
                        res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
                    } else {
                        res = Configure_Spectrometer_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
                    }
                    int total_time = res[0] * res[1];
                    lo_freq_input = [lo_freq - stepnb * step,lo_freq + stepnb * step,step];
                    Standing_wave_noretune_fm_COP(band,total_time,hrs_mode,backend,lo_freq_input,los_code[i]);
                }
            }
        }
    }
    //For band 2a, we need to add the retune case
    if(band == "2a") {
        Standing_wave_retune_COP_proc_ops(band,"both",["mr","mr"],1,"sc");
    }
}

// Interpolate differential frequency switch Allan time and exponent
//
// This might actually depend on the frequency throw, but no information
// is available. Thus a restructuring of this routine is probable.
//
double[] procedure InterpolateSpecFSwitchAllan {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    bool subband = false; // 1GHz bandwith reference instead of full IF
}{
    if(subband) {
        double[] allan = CalibrationReader("fs_Allan_subband",["spec_Allan_time","spec_Allan_exp","spec_binning_exp"],band,lo_freq);
    } else {
        allan = CalibrationReader("fs_Allan",["spec_Allan_time","spec_Allan_exp","spec_binning_exp"],band,lo_freq);
    }

    return allan;
}

//HIFI investigation of diplexer with M1, procedure
//Perform diplexer scans at a series of M1 values
//Frequencies and M1 values to use are pre-tabulated
procedure Diplexerscan_M1_proc_fm_COP {
    string band = "7b" in ["3b","7b"]; // HIFI band
    int testblock = 1 in [0,3]; //Test block for 3b and 7b
}{
    //Sanity checks: no blocks 0 and 3 for 7b
    if(band == "7b" && (testblock == 0 || testblock == 3)) {
        error("There's no such testblock allowed in 7b");
    }
    mois_comment("Start of Diplexer scan investigation in band " + band);
    mois_comment("For this test, a special LCU safety table should have been uploaded via dedicated TPF files");
    //We will loop on tabulated frequencies
    //For each we will tune LO power and do diplexer scans
    //for various M1/M2 settings for 3b and 7b
    //1. Get the list of frequencies to be used for the scan
    if(band == "7b") {
        string tab1 = "config_purity_cop_" + band + ".config";
    } else {
        tab1 = "config_M1calib_" + band + "_" + testblock + ".config";
        if(testblock == 0) {
            tab1 = "config_M1calib_" + band + "_COP.config";
            string tab2 = "config_M2calib_" + band + "_COP.config";
        }
    }
    if(band == "3b") {
        int total = table_size(tab1);
        double[] freq = [];
        double[] m1_1 = [];
        double[] m1_2 = [];
        double[] m1_3 = [];
        double[] m1_4 = [];
        double[] m1_5 = [];
        double[] m1_6 = [];
        double[] m1_7 = [];
        double[] m1_8 = [];
        double[] m2 = [];
        double[] m3 = [];
        //Read all entries
        for(int j = 1 .. total) {
            freq[j] = dlookup(tab1,"" + j,"frequency");
            m1_1[j] = dlookup(tab1,"" + j,"m1_1");
            m1_2[j] = dlookup(tab1,"" + j,"m1_2");
            m1_3[j] = dlookup(tab1,"" + j,"m1_3");
            m1_4[j] = dlookup(tab1,"" + j,"m1_4");
            m1_5[j] = dlookup(tab1,"" + j,"m1_5");
            m1_6[j] = dlookup(tab1,"" + j,"m1_6");
            m1_7[j] = dlookup(tab1,"" + j,"m1_7");
            //m1_8[j] = dlookup(tab1,"" + j,"m1_8");
            if(testblock > 0) {
                m2[j] = dlookup(tab1,"" + j,"m2_" + testblock);
                m3[j] = dlookup(tab1,"" + j,"m3_" + testblock);
            } else {
                m2[j] = dlookup(tab2,"" + j,"m2_1");
                m3[j] = dlookup(tab2,"" + j,"m3_1");
            }
            //Check whether this combination of band+freq is allowed in the current CUS
            Check_Band_vs_Freq_proc_fm(band,freq[j]);
        }
        //
    }
    mois_step("Switch-on LO band (only for testblocks 0 or 1)");
    //Only if first testblock
    if(testblock <= 1) {
        LCU_switchon_proc_spur(band);
        //Wait an extra delay of 10 min for mid term stabilization
        delay(600);
        mois_tmcheck("Check that parameter HL_Channel_S is " + band);
        //
    }
    //
    if(band == "3b") {
        mois_step("Loop on frequencies and multiplier settings");
        //Start loop on diplexer scans
        double[] m1_array = [];
        double[] m2_array = [];
        for(int i = 1 .. total) {
            //Configure FPU at that frequency
            Init_MSA_fm(band,"CLOSE",freq[i],"ON");
            //
            //Loop on M1 settings
            int nb_m1 = 7;
            int nb_m2 = 1;
            if(band == "3b") {
                m1_array = [m1_1[i],m1_2[i],m1_3[i],m1_4[i],m1_5[i],m1_6[i],m1_7[i]];
                //now work with 3 blocks of 1 M2
                m2_array = [m2[i]];
                if(testblock == 2) {
                    m2_array = [m2[i]];
                }
                if(testblock == 3) {
                    m2_array = [m2[i]];
                }
                if(testblock == 0) {
                    m2_array = [m2[i]];
                }
            }
            //
            //Loop on M1
            for(int k = 0 .. nb_m1 - 1) {
                //Loop on M2
                for(int l = 0 .. nb_m2 - 1) {
                    //Prepare for diplexer scan
                    //Use nominal diplexer values 
                    double[] result_dip = Get_Diplexer_setting(band,freq[i]);
                    Set_Diplexer_current_block_fm(result_dip[0],result_dip[1]);
                    //Set the maximum Vd2 available 
                    LCU_config_w_M1M2M3_block_fm(band,freq[i],m1_array[k],m2_array[l],m3[i]);
                    message(band + ", " + freq[i] + ", " + m1_array[k] + ", " + m2_array[l] + ", " + m3[i]);
                    //Perform diplexer scan at that frequency and M1 setting
                    double diplexer_current_min_h = -2.24;
                    double diplexer_current_max_h = 2.24;
                    double diplexer_current_step = -0.073;
                    //i.e. approx 4.48/61
                    int n_steps = 61;
                    double stepTime = 0.1;
                    //
                    //Perform 2 diplexer scans: one immediately after, and one X sec after the tuning macro
                    //so that total time between tuning macros is 1min, or 30sec between tuning macro and 2nd scan
                    Scan_diplexer_block_fm(band,diplexer_current_max_h,diplexer_current_max_h,diplexer_current_step,n_steps,stepTime);
                    //
                    //Add delay:
                    //For one minute between each tuning macro: 25sec more on average
                    //For 30sec between tuning macro and second scan: 16sec more on average
                    //Req. is now: 30sec between 2 tuning macros -> 4sec
                    delay(4);
                    //Second scan
                    Scan_diplexer_block_fm(band,diplexer_current_max_h,diplexer_current_max_h,diplexer_current_step,n_steps,stepTime);
                }
            }
            //
        }
    }
    //Band 7b measurement
    if(band == "7b") {
        //Read scan parameters for block of interest
        double lo_freq_low = dlookup(tab1,"" + testblock,"lo_freq1");
        double lo_freq_high = dlookup(tab1,"" + testblock,"lo_freq2");
        double lo_freq_step = dlookup(tab1,"" + testblock,"freq_step");
        double m1_low = dlookup(tab1,"" + testblock,"m1_low");
        double m1_step = dlookup(tab1,"" + testblock,"m1_step");
        double m2_low = dlookup(tab1,"" + testblock,"m2_low");
        double m2_high = dlookup(tab1,"" + testblock,"m2_high");
        double m2_step = dlookup(tab1,"" + testblock,"m2_step");
        //Init MSA
        Init_MSA_fm(band,"CLOSE",lo_freq_low,"ON");
        //Mixer should be biased to 3mV to avoid oscillation
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v","bias_max_h","bias_max_v"],band,lo_freq_low);
        //First go to 6mV
        Mixerbias_block_fm(result[2]{0},result[3]{0});
        //Then to 3mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
        //Loop on frequencies
        double lo_freq = lo_freq_low;
        while(lo_freq <= lo_freq_high) {
            //Whole FPU not re-configured. Only diplexers are re-adjusted
            result_dip = Get_Diplexer_setting(band,lo_freq);
            Set_Diplexer_current_block_fm(result_dip[0],result_dip[1]);
            //First set at nominal M1, M2, and best-guess Vd2
            result = ConfigurationReader("name_configlcu_b",["m1_v","m2_v"],band,lo_freq);
            double m1_7b = result[0]{0};
            double nominal_m1 = m1_7b;
            double m2_7b = result[1]{0};
            double nominal_m2 = m2_7b;
            //Get best-guess Vd2      
            result = ConfigurationReader("name_configlcutune_b",["drain2_v"],band,lo_freq);
            double drain2_v_best_guess = result[0]{0};
            //
            LCU_config_w_M1M2D2_block_fm(band,lo_freq,nominal_m1,nominal_m2,drain2_v_best_guess);
            message("Initial config at nominal settings");
            message(band + ", " + lo_freq + ", " + nominal_m1 + ", " + nominal_m2 + ", " + drain2_v_best_guess);
            //Then loop on M2 with nominal M1
            m2_7b = m2_low;
            message("Loop on M2: -12 to -8");
            while(m2_7b <= m2_high) {
                //Configure LO at these settings
                LCU_config_w_M1M2D2_block_fm(band,lo_freq,nominal_m1,m2_7b,drain2_v_best_guess);
                message(band + ", " + lo_freq + ", " + nominal_m1 + ", " + m2_7b + ", " + drain2_v_best_guess);
                m2_7b = m2_7b + m2_step;
            }
            //Finally, loop on M1 with nominal M2
            m1_7b = m1_low;
            message("Loop on M1: -8.5 to nominal");
            while(m1_7b <= nominal_m1) {
                //Configure LO at these settings
                LCU_config_w_M1M2D2_block_fm(band,lo_freq,m1_7b,nominal_m2,drain2_v_best_guess);
                message(band + ", " + lo_freq + ", " + m1_7b + ", " + nominal_m2 + ", " + drain2_v_best_guess);
                m1_7b = m1_7b + m1_step;
            }
            lo_freq = lo_freq + lo_freq_step;
        }
        //end of freq loop
        //Set nominal settings back - use safe Vd2
        double[] cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,0.0);
        LCU_config_w_M1M2D2_block_fm(band,lo_freq,nominal_m1,nominal_m2,cresult[0]);
    }
    //  
    mois_comment("At the end of this test, the standard LCU safety table should be uploaded again.");
}

// Interpolate differential sky chop Allan time and exponent
double[] procedure InterpolateSpecChopAllan {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    bool subband = false; // 1GHz bandwith reference instead of full IF
}{
    // subband is not used yet
    double[] allan = CalibrationReader("chop_Allan",["spec_Allan_time","spec_Allan_exp","spec_binning_exp"],band,lo_freq);

    return allan;
}

// IF gain and noise temperature, procedure
procedure IFcalibration {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.: at least 2sec !  
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    HKrate(1.0);
    //Get biases. No LO freq. given here.
    {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_low_resistive_h","bias_high_resistive_h","bias_low_resistive_v","bias_high_resistive_v"],band,0.0);
    double bias_low_h = result[0]{0};
    double bias_high_h = result[1]{0};
    double bias_low_v = result[2]{0};
    double bias_high_v = result[3]{0};
    //Set magnets to 0
    Set_Magnet_current_block_fm(0.0,0.0);
    //
    Spectra_resistive_low_fm(band,bias_low_h,bias_low_v,integ_time,backend);
    Spectra_resistive_high_fm(band,bias_high_h,bias_high_v,integ_time,backend);
    //Back to normal bias and normal magnets
    //Need a representative frequency: take keyfreq
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result_d[0];
    result = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v","norm_bias_h","norm_bias_v"],band,lo_freq);
    double magnet_h = result[0]{0};
    double magnet_v = result[1]{0};
    double bias_h = result[2]{0};
    double bias_v = result[3]{0};
    Mixerbias_block_fm(bias_h,bias_v);
    Set_Magnet_current_block_fm(magnet_h,magnet_v);
}

// Function computing HRS LO for SPACON check message
procedure Check_HRS_LO_proc_ops {
    string[] hrs_mode = ["wb","wb"]; //HRS resolution mode for both polar: hr, mr, lr, wb
    double hrh_up_ol1 = 4.5; // IF1 frequency for H-polar
    double hrh_up_ol2 = 4.5; // IF2 frequency for H-polar
    double hrh_up_ol3 = 4.5; // IF3 frequency for H-polar
    double hrh_up_ol4 = 4.5; // IF4 frequency for H-polar
    double hrh_down_ol5 = 10.5; // LO5 frequency for H-polar
    double hrh_down_ol6 = 1.25; // LO6 frequency for H-polar
    double hrh_down_ol7 = 490.0; // LO7 frequency for H-polar
    double hrv_up_ol1 = 4.5; // IF1 frequency for V-polar
    double hrv_up_ol2 = 4.5; // IF2 frequency for V-polar
    double hrv_up_ol3 = 4.5; // IF3 frequency for V-polar
    double hrv_up_ol4 = 4.5; // IF4 frequency for V-polar
    double hrv_down_ol5 = 10.5; // LO5 frequency for V-polar
    double hrv_down_ol6 = 1.25; // LO6 frequency for V-polar
    double hrv_down_ol7 = 490.0; // LO7 frequency for V-polar
}{
    //Initialize array
    //Defaults are: lo1=13, lo2=14, lo3=15, lo4=16 GHz
    int[] a_m_parameter = [0,64,0,64,0,64,0,64,5,51,0,49,7,0,64,0,64,0,64,0,64,5,51,0,49,7];
    int[] a_m = [0,0];
    //
    //The number of A and M parameters to compute depends on the mode
    //
    //First rename LO7 and convert to GHz
    double flo7_h = hrh_down_ol7 / 1000.0;
    double flo7_v = hrv_down_ol7 / 1000.0;
    //Initialize freq.
    double flo_u1_h = 0.0;
    double flo_u1_v = 0.0;
    double flo_l2_h = 0.0;
    double flo_l2_v = 0.0;
    double flo_u3_h = 0.0;
    double flo_u3_v = 0.0;
    double flo_l4_h = 0.0;
    double flo_l4_v = 0.0;
    //
    //Available sub-band width: as of SPR-2479
    double bw_h = flo7_h / 2.0 - 0.015;
    double bw_v = flo7_v / 2.0 - 0.015;
    //High-Resolution
    if(hrs_mode[0] == "hr") {
        //H-polar
        flo_u1_h = (9.25 - bw_h / 2.0 + hrh_up_ol1) * 1000.0;
        mois_tmcheck("Check that parameter HRH_LO1_F is " + flo_u1_h + " MHz");
    }
    //
    if(hrs_mode[1] == "hr") {
        //V-polar
        flo_u1_v = (9.25 - bw_v / 2.0 + hrv_up_ol1) * 1000.0;
        mois_tmcheck("Check that parameter HRV_LO1_F is " + flo_u1_v + " MHz");
    }
    //
    //Medium-Resolution
    if(hrs_mode[0] == "mr") {
        //H-polar
        flo_u1_h = (9.25 - bw_h / 2.0 + hrh_up_ol1) * 1000.0;
        flo_l4_h = (9.25 + bw_h / 2.0 + hrh_up_ol4) * 1000.0;
        mois_tmcheck("Check that parameters HRH_LO1_F and HRH_LO4_F are " + flo_u1_h + " and " + flo_l4_h + " MHz respectively.");
    }
    //
    //Medium-Resolution
    if(hrs_mode[1] == "mr") {
        //V-polar
        flo_u1_v = (9.25 - bw_v / 2.0 + hrv_up_ol1) * 1000.0;
        flo_l4_v = (9.25 + bw_v / 2.0 + hrv_up_ol4) * 1000.0;
        mois_tmcheck("Check that parameters HRV_LO1_F and HRV_LO4_F are " + flo_u1_v + " and " + flo_l4_v + " MHz respectively.");
    }
    //
    //Low-Resolution
    if(hrs_mode[0] == "lr") {
        //H-polar
        flo_u1_h = (9.25 - bw_h / 2.0 + hrh_up_ol1) * 1000.0;
        flo_l2_h = (9.25 + bw_h / 2.0 + hrh_up_ol2) * 1000.0;
        flo_u3_h = (9.25 - bw_h / 2.0 + hrh_up_ol3) * 1000.0;
        flo_l4_h = (9.25 + bw_h / 2.0 + hrh_up_ol4) * 1000.0;
        mois_tmcheck("Check that parameters HRH_LO1_F, HRH_LO2_F, HRH_LO3_F and HRH_LO4_F are " + flo_u1_h + ", " + flo_l2_h + ", " + flo_u3_h + " and " + flo_l4_h + " MHz respectively.");
    }
    //
    //Low-Resolution
    if(hrs_mode[1] == "lr") {
        //V-polar
        flo_u1_v = (9.25 - bw_v / 2.0 + hrv_up_ol1) * 1000.0;
        flo_l2_v = (9.25 + bw_v / 2.0 + hrv_up_ol2) * 1000.0;
        flo_u3_v = (9.25 - bw_v / 2.0 + hrv_up_ol3) * 1000.0;
        flo_l4_v = (9.25 + bw_v / 2.0 + hrv_up_ol4) * 1000.0;
        mois_tmcheck("Check that parameters HRV_LO1_F, HRV_LO2_F, HRV_LO3_F and HRV_LO4_F are " + flo_u1_v + ", " + flo_l2_v + ", " + flo_u3_v + " and " + flo_l4_v + " MHz respectively.");
    }
    //
    //Wide-Band
    if(hrs_mode[0] == "wb") {
        //H-polar
        flo_u1_h = (9.25 + hrh_up_ol1) * 1000.0;
        flo_l2_h = (9.25 + hrh_up_ol2) * 1000.0;
        flo_u3_h = (9.25 + hrh_up_ol3) * 1000.0;
        flo_l4_h = (9.25 + hrh_up_ol4) * 1000.0;
        mois_tmcheck("Check that parameters HRH_LO1_F, HRH_LO2_F, HRH_LO3_F and HRH_LO4_F are " + flo_u1_h + ", " + flo_l2_h + ", " + flo_u3_h + " and " + flo_l4_h + " MHz respectively.");
    }
    //
    //Wide-Band
    if(hrs_mode[1] == "wb") {
        //V-polar
        flo_u1_v = (9.25 + hrv_up_ol1) * 1000.0;
        flo_l2_v = (9.25 + hrv_up_ol2) * 1000.0;
        flo_u3_v = (9.25 + hrv_up_ol3) * 1000.0;
        flo_l4_v = (9.25 + hrv_up_ol4) * 1000.0;
        mois_tmcheck("Check that parameters HRV_LO1_F, HRV_LO2_F, HRV_LO3_F and HRV_LO4_F are " + flo_u1_v + ", " + flo_l2_v + ", " + flo_u3_v + " and " + flo_l4_v + " MHz respectively.");
    }
    //
    //LO5 to LO7
    //
    mois_tmcheck("Check that parameters HRH_LO5_F, HRH_LO6_F and HRH_LO7_F are " + hrh_down_ol5 * 1000.0 + ", " + hrh_down_ol6 * 1000.0 + " and " + hrh_down_ol7 + " MHz respectively.");
    mois_tmcheck("Check that parameters HRV_LO5_F, HRV_LO6_F and HRV_LO7_F are " + hrv_down_ol5 * 1000.0 + ", " + hrv_down_ol6 * 1000.0 + " and " + hrv_down_ol7 + " MHz respectively.");
}

// Standing wave analysis, mode
// Specific retune case for 2a
//HIFI-COP-3-StWv1
obs HifiEng_standing_wave_retune_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //This is only meant for band 2a
    if(band != "2a") {
        error("this test is only meant for band 2a");
    }
    //General parameters in use
    int freq_index = 1;
    string los_code = "sc";
    string backend = "both";
    string[] hrs_mode = ["mr","mr"];
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Standing_wave_retune_COP_proc_ops(band,backend,hrs_mode,freq_index,los_code));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Standing_wave_noretune_COP_proc_ops(band,backend,hrs_mode,freq_index,los_code);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// Get system temperatures for a whole array of frequencies
double[] procedure GetAllTsys {
    string band = "4a"; // HIFI band
    double[] freqgrid = [978200.0,979600.0]; // Grid of frequencies
}{
    int nstep = length(freqgrid);
    double[] tsys = [];
    for(int i = 0 .. nstep - 1) {
        tsys[i] = InterpolateTsys(band,freqgrid[i]);
    }

    return tsys;
}

//HIFI start up and reboot, mode
//Boots, and notify PDU status ON for ICU
mode HifiManCmd_startup_and_reboot {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    int partition_ID = 0; //0 if forceboot_default. Partition ID in case it should be used. 
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    Mode_status_check_switched_off();
    mois_comment("Start of Boot procedure");
    mois_step("Power ON the ICU");
    string icu_subsys = "ICU_Prime";
    if(prime_or_redundant == "Red") {
        icu_subsys = "ICU_Red";
    }
    PDU_switch_on_block_ops(icu_subsys);
    mois_step("Force boot ICU");
    HIFI_force_boot_block_ops(partition_ID);
    //check OBS version
    {double,string}[] result = ConfigurationReader("name_delays",["hi_sw_version","hi_sw_revision","hi_sw_patch"],"0",0.0);
    int hi_sw_version = iround(result[0]{0});
    int hi_sw_revision = iround(result[1]{0});
    int hi_sw_patch = iround(result[2]{0});
    mois_tmcheck("Check that HI_SW_Version is " + hi_sw_version);
    mois_tmcheck("Check that HI_SW_Revision is " + hi_sw_revision);
    mois_tmcheck("Check that HI_SW_Patch is " + hi_sw_patch);
    //
    //Get applicable HK rate
    result = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    double hk_rate = result[0]{0};
    //
    mois_step("Adjust HK data rate.");
    HKrate_block_ops(hk_rate);
    //FPU HK needs to be polled
    mois_step("Notify PDU status for FCU");
    HIFI_notify_PDU_status_on_block_ops("ON","OFF","OFF","OFF","OFF","OFF","FCU");
    StopMode_block_ops();
    // -> to issue last obsd/bbid
    Mode_status_check_intermediate();
}

//Generic procedure to obtain the data-rate computations using DataTaking
double[] procedure ILT_datarate_proc_fm {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "tp" in ["tp","slowchop","fastchop","fsw"]; //modulation mode between hot/cold: tp, slowchop, fastchop
    int integ_time = 8; //TOTAL integration time
}{
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,["wb1","wb1"],backend);
    //
    //Compute data_time and n_switch using the wrapper
    if(chopmode == "slowchop" || chopmode == "tp" || chopmode == "fsw") {
        if(chopmode == "slowchop") {
            chopmode = "chop";
        }
        if(chopmode == "fsw") {
            chopmode = "fs";
        }
        int[] res = ConfigSlowChop(integ_time,chopmode,band,0.0,backendreadoutparms);
        int data_time = res[0];
    }
    if(chopmode == "fastchop") {
        res = ConfigFastChop(integ_time,1.0,band,0.0,backendreadoutparms);
        data_time = res[0] / 2;
    }
    //
    //Compute data-rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    //

    return rates;
}

//Set LCU back to standby status without setting any particular LO band, procedure
procedure LCU0_standby_proc_fm {
    string band = "0"; // HIFI band
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

//LO parameter scan without HotCold measurement
procedure LCU_power_scan_without_Tsys {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4
    double lo_freq = 500.0; //LO frequency
    double param_min = 1.0; //Min. of scanned parameter
    double param_max = 2.0; //Max. of scanned parameter
    double step_size = 0.1; //Step size
    string param_name = "D2"; //Code of scanned parameter: M1,M2,G1,G2,D1,D2.
}{
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d1_v","d2_v"],band,lo_freq);
    double drain1_safe = cresult[0];
    double drain2_safe = cresult[1];
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //First set to nominal values
    HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_safe,curlim1_v,drain2_safe,curlim2_v,macro_checksum,config_lo_delay);
    //
    double current_param = param_min;
    //Loop up on parameter of interest, all other values set to
    //optimum value at the frequency of interest.
    while(current_param <= param_max) {
        //Identify parameter to be scanned.
        if(param_name == "M1") {
            m1_v = current_param;
        }
        if(param_name == "M2") {
            m2_v = current_param;
        }
        if(param_name == "G1") {
            gate1_v = current_param;
        }
        if(param_name == "G2") {
            gate2_v = current_param;
        }
        if(param_name == "D1") {
            drain1_v = current_param;
        }
        if(param_name == "D2") {
            drain2_v = current_param;
        }
        HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,config_lo_delay);
        current_param = current_param + step_size;
        //
    }
    //Back to nominal values
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    plevel_v = result[0]{0};
    m1_v = result[1]{0};
    m2_v = result[2]{0};
    m3_v = result[3]{0};
    d2_step = iround(result[4]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    gate1_v = cresult[0];
    gate2_v = cresult[1];
    drain1_v = cresult[2];
    drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    freq_nx = iround(result[0]{0});
    //Compute lsu_main and offset
    resu = ComputeLSU_A_M_R(band,lo_freq);
    lsu_main = resu[0];
    lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    macro_checksum = iround(result[0]{0});
    //
    HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_safe,curlim1_v,drain2_safe,curlim2_v,macro_checksum,config_lo_delay);
    //
}

//HIFI-FCP-HC1: chopper health check#2
obs HifiEng_Chopper_FT2_COP {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Chopper_FT2_COP_proc_ops(prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Chopper_FT2_COP_proc_ops(prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// Needs the chopper in open-loop mode !!
block Chopper_openloop_set_block_fm HIFI 3693 {
    int position = 0 in [0,1];
}{
    //Start_block ();
    int rot = 2048 + 70 * position;
    HIFI_CPR_Chopper_Rot_RAW_proc_fm(rot);
    //Rotate chopper
    Hifi_HIFI_non_periodic_hk_FCU();
    //To get sent value
    delay(2);
}

// Procedure to compute all parameters needed in a Configure_spectroscopy
// This is a special version for IST, not to be used in normal AOTs
// see HIFI SCRs 1029 and 1483
{int,int,int,int,int,int,int,int,int,int} procedure ConfigureSpectroscopyParams_IST {
    /* Integration time */
    int data_time = 4; // Integration time between two data readouts
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string chopmode = "chop" in ["chop","lchop","fs","hot-cold","tp","chopcal"]; // Chop mode determining the modulation dead time
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used,channel windows}
}{
    // Get fixed parameters from configuration and calibration files
    // Command jitter time is the default delay 
    {double,string}[] result = ConfigurationReader("name_delays",["add_jitter"],band,lo_freq);
    int add_jitter = iround(result[0]{0});
    // WBS delta time 
    // Default total power. This should be 0.
    int del_wbs = add_jitter;
    // WBS delta time given by switch dead time
    if(chopmode == "chop") {
        double res = GetSkyChopDeadTime(band,lo_freq);
        del_wbs = iceil(res * 1000.0);
    }
    if(chopmode == "lchop") {
        res = GetLoadChopDeadTime(band,lo_freq);
        del_wbs = iceil(res * 1000.0);
    }
    if(chopmode == "fs") {
        res = GetFSwitchDeadTime(band,lo_freq);
        del_wbs = iceil(res * 1000.0);
    }
    if(chopmode == "chopcal") {
        res = GetHotColdDeadTime(band,lo_freq);
        del_wbs = iceil(res * 1000.0);
    }
    if(chopmode == "hot-cold") {
        bool wbsused = backendreadoutparms{2}{0} || backendreadoutparms{3}{0};
        res = HotColdRelaxTime(band,lo_freq,wbsused);
        del_wbs = iceil(res * 1000.0);
    }
    // HRS delta time - should be zero as well
    int del_hrs = add_jitter;
    // Additional delays in the readout loops - given in OBS user manual
    result = ConfigurationReader("name_delays",["add_hrs","add_wbs","add_jitter","wbs_init","wbs_chunksize","tacc_add","hrs_phase","min_wbs_acc","stdchop_phase"],band,lo_freq);
    int add_hrs = iround(result[0]{0});
    int add_wbs = iround(result[1]{0});
    int wbs_init = iround(result[3]{0});
    int wbs_chunksize = iround(result[4]{0});
    int tacc_add = iround(result[5]{0});
    int hrs_phase = iround(result[6]{0});
    // HRS standard phase length
    int min_wbs_acc = iround(result[7]{0});
    // WBS transfer time
    int stdchopphase = iround(result[8]{0});
    // Split total integration time
    int tint = data_time * n_data * 1000;
    int n_wbs_integr = data_time * 1000 / stdchopphase;
    // dead time has to be an integer multiple of the 10ms chunk time
    int tdead = del_wbs + add_wbs + add_jitter;
    int nchunk = (tdead - 1) / wbs_chunksize + 1;
    int tcorr = nchunk * wbs_chunksize - tdead;
    del_wbs = del_wbs + tcorr;
    tdead = tdead + tcorr;
    // Accumulation time
    // Ignores that total power can be slightly more efficient
    int t_acc_wbs = (tint - wbs_init) / (n_data * n_wbs_integr) - tdead;
    // discretize in 10ms chunks
    nchunk = (t_acc_wbs - tacc_add) / wbs_chunksize;
    t_acc_wbs = nchunk * wbs_chunksize + tacc_add;
    // Check relative to minimum accumulation tim
    if(t_acc_wbs + del_wbs + add_wbs < min_wbs_acc + add_jitter) {
        SError("WBS integration too short for readout. Increase duration.");
    }
    int n_wbs_start = n_data * n_wbs_integr;
    // HRS
    int hrs_fullphase = hrs_phase + del_hrs + add_hrs;
    int r_hrs = (t_acc_wbs + hrs_fullphase - add_jitter) / hrs_fullphase;
    int t_acc_hrs = (t_acc_wbs - add_jitter) / r_hrs - del_hrs - add_hrs;
    // for n_wbs_integr=1 identical to r_hrs
    int n_hrs_integr = r_hrs * n_wbs_integr;
    // Compute actual integration time and dead time per readout
    // If WBS is used count only the WBS time
    if(backendreadoutparms{2}{0} || backendreadoutparms{3}{0}) {
        int tint_act = nchunk * wbs_chunksize * n_data * n_wbs_integr;
        tdead = tdead + tacc_add;
    } else {
        tint_act = t_acc_hrs * r_hrs * n_data * n_wbs_integr;
        tdead = tdead + r_hrs * (del_hrs + add_hrs) + add_jitter;
    }
    // Return all config_spectroscopy timing parameters

    return {n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,tdead,tint_act};
}

// WBS attenuator tuning, block
// Both polarizations are treated
block WBS_tune_block_fm HIFI 3603 {
    string band = "1a"; // HIFI band
    int tune_target = 80 in [10,85]; //target illumination percentage
}{
    //Start_block(); 
    //
    //Tune attenuators.
    Hifi_HIFI_Tune_WBS($BBID,tune_target);
    //Get delay
    {double,string}[] result_d = ConfigurationReader("name_delays",["wbs_tune_delay"],band,0.0);
    int wbs_tune_delay = iround(result_d[0]{0});
    delay(wbs_tune_delay);
    //
}

//Force boot, block
block HIFI_force_boot_block_fm HIFI 3600 {
    int partition_ID = 0; //0 if forceboot_default. Partition ID in case it should be used. 
}{
    if(partition_ID == 0) {
        Hifi_HIFI_force_bootdefault();
    } else {
        Hifi_HIFI_force_bootpartition(partition_ID);
    }
    //Increase delay - SPR-1354
    delay(5);
    //This is not standard practice but here we can only start
    //to stamp HKs with obsid/bbid pair after ICU is up and running
    Start_block_no_hk_request();
}

//TM check when intermediate
procedure Mode_status_check_intermediate {
}{
    mois_comment("Checking instrument status in intermediate mode");
    //Get applicable HK rate
    {double,string}[] result_d = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    string hk_rate = result_d[0]{1};
    mois_tmcheck("Check that HIFI telemetry packets (3,25,1025)- HIFI_PERIODIC_HK - are arriving at a " + hk_rate + " rate.");
}

// General version used in non-spectral scan FSW modes
procedure DoubleLoadMeasurement {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double lo_freq = 978200.0; // LO frequency
    double freq_throw = -40.0; // throw of frequency switch in MHz
    double deltanu = 1.0; // minimum effective resolution of the calibrated data
    int data_time = 4; // time between subsequent data readouts
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
}{
    // Call generic version with fixed parameters
    SScanDoubleLoadMeasurement(band,lo_freq,lo_freq,freq_throw,true,deltanu,data_time,backendreadoutparms);
}

// Get dead time for chopper motion between HBB and CBB
double procedure GetHotColdDeadTime {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] dead = CalibrationReader("hotcold_deadtime",["hotcold"],band,lo_freq);

    return dead[0];
}

// HRS complete configuration with minimum attenuation, block
// Both polarizations are treated
block HRS_config_min_att_block_fm HIFI 3635 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    //Start_block();
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrh_up_ol1_m = a_m_parameter[1];
    int hrh_up_ol1_a = a_m_parameter[0];
    int hrh_up_ol2_m = a_m_parameter[3];
    int hrh_up_ol2_a = a_m_parameter[2];
    int hrh_up_ol3_m = a_m_parameter[5];
    int hrh_up_ol3_a = a_m_parameter[4];
    int hrh_up_ol4_m = a_m_parameter[7];
    int hrh_up_ol4_a = a_m_parameter[6];
    int hrh_down_ol5_m = a_m_parameter[9];
    int hrh_down_ol5_a = a_m_parameter[8];
    int hrh_down_ol6_m = a_m_parameter[11];
    int hrh_down_ol6_a = a_m_parameter[10];
    int hrh_down_ol7_m = a_m_parameter[12];
    //V-polar
    //V-polar
    int hrv_up_ol1_m = a_m_parameter[14];
    int hrv_up_ol1_a = a_m_parameter[13];
    int hrv_up_ol2_m = a_m_parameter[16];
    int hrv_up_ol2_a = a_m_parameter[15];
    int hrv_up_ol3_m = a_m_parameter[18];
    int hrv_up_ol3_a = a_m_parameter[17];
    int hrv_up_ol4_m = a_m_parameter[20];
    int hrv_up_ol4_a = a_m_parameter[19];
    int hrv_down_ol5_m = a_m_parameter[22];
    int hrv_down_ol5_a = a_m_parameter[21];
    int hrv_down_ol6_m = a_m_parameter[24];
    int hrv_down_ol6_a = a_m_parameter[23];
    int hrv_down_ol7_m = a_m_parameter[25];
    //Attenuators are fixed
    //H-polar
    double hrh_1u_att = 0.0;
    double hrh_1l_att = 0.0;
    double hrh_2u_att = 0.0;
    double hrh_2l_att = 0.0;
    double hrh_3u_att = 0.0;
    double hrh_3l_att = 0.0;
    double hrh_4u_att = 0.0;
    double hrh_4l_att = 0.0;
    //V-polar    
    double hrv_1u_att = 0.0;
    double hrv_1l_att = 0.0;
    double hrv_2u_att = 0.0;
    double hrv_2l_att = 0.0;
    double hrv_3u_att = 0.0;
    double hrv_3l_att = 0.0;
    double hrv_4u_att = 0.0;
    double hrv_4l_att = 0.0;
    //Configure HRS-H
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrh_1u_att,hrh_1l_att,hrh_2u_att,hrh_2l_att,hrh_3u_att,hrh_3l_att,hrh_4u_att,hrh_4l_att,hrh_up_ol1_m,hrh_up_ol1_a,hrh_up_ol2_m,hrh_up_ol2_a,hrh_up_ol3_m,hrh_up_ol3_a,hrh_up_ol4_m,hrh_up_ol4_a,hrh_down_ol5_m,hrh_down_ol5_a,hrh_down_ol6_m,hrh_down_ol6_a,hrh_down_ol7_m);
    //delay(hrs_config_delay);
    //
    //Configure HRS-V
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrv_1u_att,hrv_1l_att,hrv_2u_att,hrv_2l_att,hrv_3u_att,hrv_3l_att,hrv_4u_att,hrv_4l_att,hrv_up_ol1_m,hrv_up_ol1_a,hrv_up_ol2_m,hrv_up_ol2_a,hrv_up_ol3_m,hrv_up_ol3_a,hrv_up_ol4_m,hrv_up_ol4_a,hrv_down_ol5_m,hrv_down_ol5_a,hrv_down_ol6_m,hrv_down_ol6_a,hrv_down_ol7_m);
    delay(hrs_config_delay);
    //
    //Now Configure blocks
    HRS_config_resol_fm(band,hrs_mode);
}

//Startblock
procedure StartBlock_ops {
}{
    //This will only be used if the first TC in a block does
    //not has argument $BBID
    mois_spacon("In the following command, the second parameter (OBS_ID) shall be replaced by a Formal Parameter value according to the list provided by the instrument ICC.");
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
}

//HIFI-COP-3-Tsys
obs HifiEng_Tsys_COP {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //General parameters in use
    int integ_time = 4;
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    int n_wbs1 = 0;
    int n_hrs_trans = 0;
    string chopmode = "slowchop";
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Tsys_COP_proc_ops(band,integ_time,backend,hrs_mode,n_wbs1,n_hrs_trans,chopmode));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Tsys_COP_proc_ops(band,integ_time,backend,hrs_mode,n_wbs1,n_hrs_trans,chopmode);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//  LCU configuration AT START-UP into NOMINAL mode, procedure
//  Uses SFT approach with safe call for 3b, BUT combined TM page dump
procedure LCU_switchon_proc_spur {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //Clear potential failure mode
    Set_LO_Nominal_block_fm();
    //
    //We use a constant frequency for each band, regardless of the input
    double lo_freq = 0.0;
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq","midfreq","keyfreqwarm","keyfreq_dummy"],band,0.0);
    lo_freq = result_d[0];
    //this is for cold operations
    //   lo_freq = result_d[2];   //this is for warm operations
    //   lo_freq = result_d[3];     //this is for dummy operations
    ////FM_CUS_11.5: replace keyfreq by the only allowed frequency for warm IST
    //For band 7b, 1723.5 may be problematic. Take mid freq. instead
    //if (band == "7b") {
    //  lo_freq = result_d[1];  
    //  }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_confindex = "name_confindex_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["switch_on_delay","config_lo_delay"],band,lo_freq);
    int switch_on_delay = iround(result[0]{0});
    int config_lo_delay = iround(result[1]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    drain2_v = cresult[0];
    //Send command: expect that we have already switched to NOMINAL
    //We set D2 to best guess and wait some time to stabilize chain temperature
    HIFI_Configure_LCU_block_spur(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,switch_on_delay);
    //
    //Set heater to their switch-on value
    HL_heater_block_fm(band,"nominal");
}

// WBS stand-by, block
block WBS_standby_block_aot HIFI 6703 {
    string laser = "ON" in ["ON","OFF"]; //laser status: if ON, read from configwbs.config
}{
    //Set zero ON
    Hifi_HIFI_switch_zero_WBS_H($BBID,"ON");
    Hifi_HIFI_switch_zero_WBS_V($BBID,"ON");
    delay(1);
    //Standby configuration
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s"],"0",0.0);
    string hwh_laser1_s = result_d[0]{1};
    string hwh_laser2_s = result_d[1]{1};
    if(laser == "OFF") {
        hwh_laser1_s = "OFF";
        hwh_laser2_s = "OFF";
    }
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    //
    int hwh_att_band4 = 7;
    int hwh_att_band3 = 7;
    int hwh_att_band2 = 7;
    int hwh_att_band1 = 7;
    int hwh_att_in = 15;
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    {double,string}[] result = ConfigurationReader("name_delays",["wbs_config_delay"],"0",0.0);
    int wbs_config_delay = iround(result[0]{0});
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s"],"0",0.0);
    string hwv_laser1_s = result_d[0]{1};
    string hwv_laser2_s = result_d[1]{1};
    if(laser == "OFF") {
        hwv_laser1_s = "OFF";
        hwv_laser2_s = "OFF";
    }
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    //
    int hwv_att_band4 = 7;
    int hwv_att_band3 = 7;
    int hwv_att_band2 = 7;
    int hwv_att_band1 = 7;
    int hwv_att_in = 15;
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
}

/////////////////////////////////////////////////////////////////
// Stability parameters
// Interpolate system Allan time and exponent for the selected frequency
double[] procedure InterpolateSpecAllan {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    bool subband = false; // 1GHz bandwith reference instead of full IF
}{
    if(subband) {
        double[] allan = CalibrationReader("system_Allan_subband",["spec_Allan_time","spec_Allan_exp","spec_binning_exp"],band,lo_freq);
    } else {
        allan = CalibrationReader("system_Allan",["spec_Allan_time","spec_Allan_exp","spec_binning_exp"],band,lo_freq);
    }

    return allan;
}

// Drift noise from an OTF sequence
// This is still to be scaled by a factor 1.0/(B_fluct*T_A)
double procedure OtfDrift {
    double x = 0.02; // integration time (everything relative to the Allan time)
    double xr = 0.06; // reference integration time
    double d1 = 0.3; // time difference between last OFF and point
    double d2 = 0.3; // time difference between point and next OFF
    double alpha = 2.5; // drift exponent
}{
    if(x > 0.0) {
        // Auxiliary quantities for computation
        double b1 = alpha - 1.0;
        double a1 = alpha + 1.0;
        double l = (d2 + 0.5 * (xr + x)) / (d1 + d2 + xr + x);
        double ladd = 1.0 - 2.0 * l + 2.0 * l * l;
        double xi = d1 + d2 + x;
        // tscan
        // Now the drift noise variance
        double y = (-pow(x,b1) - ladd * pow(xr,b1) - l * (1.0 - l) * (pow(2.0 * xr + xi,a1) - 2.0 * pow(xr + xi,a1) + pow(xi,a1)) / (xr * xr) + l * (pow(x + xr + d1,a1) - pow(xr + d1,a1) - pow(x + d1,a1) + pow(d1,a1)) / (xr * x) + (1.0 - l) * (pow(x + xr + d2,a1) - pow(xr + d2,a1) - pow(x + d2,a1) + pow(d2,a1)) / (xr * x)) / (pow(2.0,alpha) - 2.0);
    } else {
        // forbid x values <=0
        y = 1.0E11 * (1.0 - x);
    }

    return y;
}

/////////////////////////////////////////////////////////////////
// Routines using the generic reader
// A possible frequency dependence is hidden behind the reader
/////////////////////////////////////////////////////////////////
// Interpolate system temperature for the selected frequency
// System temperature is always double sideband system temperature
double procedure InterpolateTsys {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] tsys = CalibrationReader("tsys",["tsys_h","tsys_v"],band,lo_freq);
    double combined = 1.0 / (tsys[0] * tsys[0]) + 1.0 / (tsys[1] * tsys[1]);

    return 1.0 / sqrt(combined);
}

//HIFI-COP-1.2-LO_FT
obs HifiEng_LO_FT_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(LO_FT_COP_proc_sft(band,prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            LO_FT_COP_proc_sft(band,prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

// Get number which is an integer multiple or divisor
int procedure IMultiple {
    int i = 1; // input variable
    int n = 10; // field size
}{
    int retval = imax(i,1);
    if(i > n) {
        retval = n * (i / n);
    } else {
        while(n % retval != 0) {
            retval = retval - 1;
        }
    }

    return retval;
}

//  LCU6Hb configuration into SAFE mode, procedure
procedure LCU6Hb_config_safe_proc_fm {
    string band = "7b"; // HIFI band
    double lo_freq = 1800.0 in [1800.0,1910.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

// Perform load chop integration at ON position
block HIFILoadChopOnIntegration HIFI 6035 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_slow_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_cold","chop_M3"],rates);
}

// Fast-chop
procedure HIFI_Spectr_fast_chop_proc_aot {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // readout cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    string[] phases = ["chop_M3left","chop_M3right"]; // identifiers for chopper positions
    int[] parms = [1,0]; // Parameters for chop cycles
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    //Get appropriate chopper voltages
    {bool,double,double} chopparms = GetChopVoltages(band,lo_freq,phases[0],phases[1]);
    bool isPrime = chopparms{0};
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    // Call command
    if(isPrime) {
        Hifi_HIFI_P_Spectr_fast_chop($BBID,chopparms{1},chopparms{2},parms[0],parms[1]);
    } else {
        Hifi_HIFI_R_Spectr_fast_chop($BBID,chopparms{1},chopparms{2},parms[0],parms[1]);
    }
    delay(n_cycle * data_time);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// HRS partial configuration, block
// Configures the LO and attenuators
block HRS_config_att_lo_block_fm HIFI 3624 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["mr","mr"]; //HRS resolution code
}{
    //Start_block();
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double hrsH_ATT_U1 = result[1]{0};
    double hrsH_ATT_L1 = result[2]{0};
    double hrsH_ATT_U2 = result[3]{0};
    double hrsH_ATT_L2 = result[4]{0};
    double hrsH_ATT_U3 = result[5]{0};
    double hrsH_ATT_L3 = result[6]{0};
    double hrsH_ATT_U4 = result[7]{0};
    double hrsH_ATT_L4 = result[8]{0};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double hrsV_ATT_U1 = result[1]{0};
    double hrsV_ATT_L1 = result[2]{0};
    double hrsV_ATT_U2 = result[3]{0};
    double hrsV_ATT_L2 = result[4]{0};
    double hrsV_ATT_U3 = result[5]{0};
    double hrsV_ATT_L3 = result[6]{0};
    double hrsV_ATT_U4 = result[7]{0};
    double hrsV_ATT_L4 = result[8]{0};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_ATT_U1,hrsH_ATT_L1,hrsH_ATT_U2,hrsH_ATT_L2,hrsH_ATT_U3,hrsH_ATT_L3,hrsH_ATT_U4,hrsH_ATT_L4,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
    // 
    //delay(hrs_config_delay);
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsV_ATT_U1,hrsV_ATT_L1,hrsV_ATT_U2,hrsV_ATT_L2,hrsV_ATT_U3,hrsV_ATT_L3,hrsV_ATT_U4,hrsV_ATT_L4,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
    // 
    delay(hrs_config_delay);
}

// Operating the shutter from a procedure
procedure Shutter_rotate_proc_fm {
    string shutter_state = "open" in ["open","closed"]; //Shutter state: open or closed
}{
    //HifiIltEgse_FPU_set_shutter($BBID,shutter_state); 
    delay(1);
}

// Get frequency resolution needed to measure standing wave pattern
// in frequency switch measurements
//
// This might actually depend on the frequency throw, but no information
// is available. Thus a restructuring of this routine is probable.
//
double procedure GetFSwitchSWResolution {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] dead = CalibrationReader("fsswresolution",["resolution"],band,lo_freq);

    return dead[0];
}

//HIFI-COP-1.2-UPC_FT
procedure UPC_FT_COP_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_comment("Start of HIFI Up-converter Functional Test");
    mois_comment("Please check that instrument was switched on with the " + prime_or_redundant + " unit");
    //General parameters in use
    string band = "6a";
    double lo_freq = 1568.0;
    //LO frequency
    string hbb_heater = "ON";
    //hot source on/off
    string chopper_loop = "CLOSE";
    //
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    //
    mois_step("Init FPU");
    Init_MSA_ops(band,chopper_loop,lo_freq,result[0]{0},hbb_heater,prime_or_redundant);
    mois_tmcheck("Check that parameter HF_DH1_MXBAND and HF_DV1_MXBAND are both 6");
    //
    mois_step("Take WBS spectrum with high biases");
    //Use high biases
    result = ConfigurationReader("name_confilfpu",["bias_high_resistive_h","bias_high_resistive_v"],band,lo_freq);
    Mixerbias_block_fm(result[0]{0},result[1]{0});
    mois_tmcheck("Check that parameters HF_AH1_MXBIAS_V and HF_AV1_MXBIAS_V are set to " + result[0]{0} + " and " + result[1]{0} + " mV respectively");
    //Take WBS spectrum via tuning
    WBS_tune_proc_fm(band);
    //To check final attenuator settings
    string backend = "wbs";
    int integ_time = 4;
    Configure_Spectrometer_proc_fm(band,integ_time,["wb1","wb1"],backend);
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
    //
}

//Check consistency between band and frequency inputs
//Should be invoked at the beginning of every mode !
bool procedure Check_Band_vs_WarmFreq_proc_fm {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band   
    double lo_freq = 500.0; //LO frequency
}{
    bool go_ahead_warm = true;
    //only limited amount of frequencies allowed in config files
    if(lo_freq >= 1116.0) {
        //Fetch allowed LO frequencies
        string tab = "configlcu" + band + ".config";
        int nb_freq = table_size(tab);
        double[] allFreq = dcolumn(tab,"freq");
        //Check input frequency is within the list
        int freq_in_list_count = 0;
        for(int index = 1 .. nb_freq) {
            if(lo_freq == allFreq[index - 1]) {
                freq_in_list_count = 1;
            }
        }
        //
        if(freq_in_list_count == 0) {
            error("LO frequency not in list of allowed frequencies for warm operations in band " + band);
            go_ahead_warm = false;
        }
    }

    return go_ahead_warm;
}

/////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing for the mode
// 
{int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},double,double} procedure PositionSwitch_post_timing {
    {int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} pre_timing = {12,12,13,13,21,11,1800,32,1,1,0,0,false,false,50,0}; // pre_timing parameter list
    int[] telescopetimes = [300,180,20,1,21,0];
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF cycles
}{
    // Get all values from the pre_timing section
    int inttime = pre_timing{0};
    int pointing = pre_timing{2};
    int loadlength = pre_timing{4};
    int halfloadlength = pre_timing{5};
    int load_spacing = pre_timing{6};
    int n_loadinterval = pre_timing{7};
    bool final_load = pre_timing{12};
    int initlength = pre_timing{14};
    int dangling = pre_timing{15};
    // dummy parameters
    int n_seq = pre_timing{8};
    int n_load = pre_timing{10};
    // Get all values from the telescope section
    int telinit = telescopetimes[1];
    // Initial slew time
    int slewtime = telescopetimes[2];
    // Slew time to OFF
    int longslew = telescopetimes[4];
    // Actual slew time for load slew
    int pointwaittime = telescopetimes[3];
    // Idle time between two phases
    int tend = telescopetimes[5];
    // Final deceleration time
    // treat pointwaittime like an additional slew dead time in cycles
    slewtime = slewtime + pointwaittime;
    longslew = longslew + pointwaittime;
    // Now we can compute the true scan time
    int scan_time = 2 * pointing + slewtime;
    // Check for reasonable scan times
    if(scan_time > load_spacing + slewtime) {
        SError("Phase length too long relative to load period.");
    }
    // Finally I can compute the true load interval
    n_loadinterval = imax((load_spacing + slewtime) / scan_time,1);
    // Compute duration of measurement and average scan length
    // Compute total dead time in one pointing cycle including load overhead
    int scan_time_long = 2 * pointing + longslew;
    int n_long = n_cycles / n_loadinterval;
    int looplength = (n_cycles - n_long) * scan_time + n_long * scan_time_long;
    double tscan = double(looplength) / double(n_cycles);
    // Get pointing dead time, instrument dead time is added later
    double tdead = tscan - double(2 * inttime);
    // Determine need for final load measurement
    double rest = double(n_cycles % n_loadinterval) + 0.5;
    final_load = rest > 0.5001 * double(n_loadinterval);
    // Add dangling load time
    if(final_load) {
        dangling = loadlength;
    }
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    // Compute total duration, remove pointwaittime for last slew
    // The initial time is no longer contained in the total time  
    //int totaltime=imax(initlength,telinit);
    int totaltime = looplength + dangling - pointwaittime + tend;
    // show gyro-propagation messages
    GCPMessages(pointing,2 * scan_time_long,tend);
    // Return all the times needed in the telescope and instrument modules

    return {totaltime,{inttime,inttime,pointing,pointing,loadlength,halfloadlength,load_spacing,n_loadinterval,n_seq,n_seq,n_load,n_load,final_load,final_load,initlength,dangling},tscan,tdead};
}

// Procedure to compute detailed pre timing for the version of the
// load chop mode used in LO switch-on
{int,int,int,int,int,int} procedure SwitchOnLoadChop_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    bool spectrChop = true; // whether the subsequent AOR is chopped+spectroscopic
}{
    // Determine parameters of stabilization observation
    // Get total stabilization time determining the duration of the mode
    if(spectrChop) {
        string stabilization = "stabilize_chop";
    } else {
        stabilization = "stabilize_ps";
    }
    double[] tunewait = CalibrationReader("tunetime",[stabilization,"retunelo"],band,lo_freq);
    int modelength = iceil(tunewait[0]);
    int retuneinterval = iceil(tunewait[1]);
    // Normal load-chop-noref pre_timing
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Duration of initial set up
    int initlength = duration(HIFIInitObs());
    // Add time for HK readout
    int hkduration = duration(HIFISetHK("normal",false));
    initlength = initlength + 2 * hkduration;
    // Get time for actual LO switch-on
    initlength = initlength + duration(LCU_switchon_proc_aot(band,lo_freq / 1000.0));
    // Times for additional actions after LO switch on
    int addinitlength = loadlength;
    // Add time for Mixer setup, LO tuning, Deflux
    addinitlength = addinitlength + duration(Init_Mixing_proc_aot(band,lo_freq / 1000.0)) + duration(Deflux_SingleBand_proc_aot(band,lo_freq / 1000.0));
    // Add times for backend tuning
    string target_name = "normal";
    if(wbs1{0} || wbs2{0}) {
        addinitlength = addinitlength + duration(WBS_attenuators_block(band,lo_freq / 1000.0,target_name,false));
    }
    if(hrs1{0} || hrs2{0}) {
        addinitlength = addinitlength + duration(HRS_tune_block_aot(band));
    }
    // increase initialization time by additional actions, reduce measurement time
    initlength = initlength + addinitlength;
    modelength = modelength - addinitlength;
    // Second step - LO retuning after 5 minutes if covered
    int retuneduration = duration(HIFITuneFreq(band,lo_freq,false,""));
    if(modelength + addinitlength > retuneinterval) {
        int modelength1 = imax(retuneinterval - retuneduration - addinitlength,0);
        int n_cycles1 = imax(modelength1 / (2 * data_time),1);
        // Get number of cycles needed to cover waiting time
        modelength = modelength - modelength1 - retuneduration;
        int n_cycles = imax(modelength / (2 * data_time),1);
        // Compute parameters for the instrument timing
        int on_inttime = 2 * (n_cycles + n_cycles1) * data_time + retuneduration + readoutdead;
        int on_pointing = on_inttime + imax(readoutdead,jitterdead);
    } else {
        n_cycles1 = 0;
        n_cycles = imax(modelength / (2 * data_time),1);
        on_inttime = 2 * n_cycles * data_time;
        on_pointing = on_inttime + imax(readoutdead,jitterdead);
    }
    // Compute total times
    int looplength = on_pointing;
    // dangling load time
    int dangling = loadlength;
    int closelength = duration(HIFICloseObs());
    dangling = dangling + closelength;
    // Compute total duration
    int totaltime = initlength + looplength + dangling;
    // return resorted data set

    return {totaltime,on_pointing,initlength,dangling,n_cycles1,n_cycles};
}

///////////////////////////////////////
// OBSOLETE: DO NOT USE
// Integrate with only backends, block
// We take 1 spectrum per phase.
block Stability_backend_fastchop_fm HIFI 3418 {
}{
    Start_block();
    error("Stability_backend_fastchop_fm mode is removed. Do not use");
}

//HIFI-COP-7-EngInv: Investigation time - placeholder for planning
procedure EngInv_COP_proc_ops {
    int test_duration = 3600; //duration in seconds
}{
    //
    delay(test_duration);
    //
}

// Diplexer calibration for a given mixer band
// uses a list of pre-defined frequencies where to measure
// the diplexer scan. Each scan is done at 5 D2 voltage (no LO tuning)
procedure Diplexer_calibration_vs_D2_proc_fm {
    string band = "3" in ["3","4","6","7"]; // HIFI mixer band
}{
    //
    //Get the list of frequencies to be used for the scan
    string tab = "configdipcalib_" + band + ".config";
    int total = table_size(tab);
    double[] freq = [];
    string[] subband = [];
    for(int j = 1 .. total) {
        freq[j] = dlookup(tab,"" + j,"frequency");
        subband[j] = slookup(tab,"" + j,"subband");
        //Check whether this combination of band+freq is allowed in the current CUS
        Check_Band_vs_Freq_proc_fm(subband[j],freq[j]);
    }
    //
    //configure FPU
    Init_MSA_HBB_fm(subband[1],"CLOSE",freq[1],"ON");
    //In case of band 6 or 7, use special biases
    if(band == "6" || band == "7") {
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v","bias_max_h","bias_max_v"],subband[1],freq[1]);
        //First go to 4mV
        Mixerbias_block_fm(result[2]{0},result[3]{0});
        //Then to 3mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //      
    string current_subband = "0";
    //Start loop on diplexer scans
    for(int i = 1 .. total) {
        //First check whether one needs to switch on another LO band
        if(subband[i] != current_subband) {
            LCU_switchon_proc_fm(subband[i]);
            //Wait an extra delay of 1 min for short term stabilization
            delay(60);
            current_subband = subband[i];
        }
        //Diplexer scan parameters
        double diplexer_current_min_h = -2.24;
        double diplexer_current_max_h = 2.24;
        double diplexer_current_step = -0.073;
        //i.e. approx 4.48/61
        int n_steps = 61;
        double stepTime = 0.1;
        //
        //Now loop on various D2 voltage to ensure correct pumping
        //level during at least one scan. We consider 5 to 7 points between
        //safe value and BLUE MAX
        string name_confindex = "name_confindex_a";
        if(subband[i] == "1b" || subband[i] == "2b" || subband[i] == "3b" || subband[i] == "4b" || subband[i] == "5b" || subband[i] == "6b" || subband[i] == "7b") {
            name_confindex = "name_confindex_b";
        }
        result = ConfigurationReader(name_confindex,["freq_nx"],subband[i],freq[i]);
        int freq_nx = ifloor(result[0]{0});
        double[] cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],subband[i],0.0);
        double drain2_safe = cresult[0];
        //  
        double drain2_max = Get_BLUE_LIMIT_D2_proc_fm(subband[i],freq[i]);
        double drain2_v_start = drain2_safe;
        //
        //For bands 6 to 7, start above safe value
        if(band == "6" || band == "7") {
            drain2_v_start = drain2_safe + 0.45;
            //i.e. go to 1.7
            //Need to check that drain2_v_start has not got above the blue max
            //If so, the range to scan is not so big so we stick to the safe value
            //as minimum drain2 for the scan
            if(drain2_v_start >= drain2_max) {
                drain2_v_start = drain2_safe;
            }
        }
        //
        double drain2_V = drain2_v_start;
        //Configure FPU at that frequency: except for bands 6 and 7, and except first loop
        if(band != "6" && band != "7" && i != 1) {
            Init_MSA_fm(subband[i],"CLOSE",freq[i],"ON");
        }
        //
        //Start loop on D2: number of Vd2 values depends on band
        int npoints = 5;
        if(band == "6" || band == "7") {
            npoints = 7;
        }
        for(int ii = 0 .. npoints - 1) {
            //Set d2 voltage
            drain2_V = drain2_v_start + double(ii) / double(npoints - 1) * (drain2_max - drain2_v_start);
            //message(subband[i]+", "+freq[i]+", "+drain2_V+", "+freq_nx+", "+drain2_max);
            LCU_config_nominal_w_D2_proc_fm(subband[i],freq[i],drain2_V);
            //Run scan
            Scan_diplexer_block_fm(subband[i],diplexer_current_max_h,diplexer_current_max_h,diplexer_current_step,n_steps,stepTime);
            //Run reverse scan
            Scan_diplexer_block_fm(subband[i],diplexer_current_min_h,diplexer_current_min_h,-1.0 * diplexer_current_step,n_steps,stepTime);
            //LCU_CLEAR_ERROR_block_fm();
            if(band == "6" || band == "7") {
                //Additional characterisation of mixer current between 3 and 0.6mV bias for 10 diplexer currents
                string tab2 = "config_HEB_Imix.config";
                double bandnb = GetBandCode(subband[i]);
                double lofreq_imixcal = dlookup(tab2,"" + iround(bandnb),"frequency");
                if(freq[i] == lofreq_imixcal && ii == npoints - 1) {
                    HEB_Imix_calibration_block_fm(subband[i],freq[i]);
                    //Get back to 3mV for further frequencies
                    result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v","bias_max_h","bias_max_v"],subband[1],freq[1]);
                    //First go to 4mV
                    Mixerbias_block_fm(result[2]{0},result[3]{0});
                    //Then to 3mV
                    Mixerbias_block_fm(result[0]{0},result[1]{0});
                }
            }
        }
        //
    }
    //
    //In case of band 6 or 7,go back to nominal values
    if(band == "6" || band == "7") {
        result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],subband[1],freq[1]);
        //First go to 4mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
        //Then to nominal
        result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],subband[1],freq[1]);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CUS scripts for WBS.
// WBS FT scripts are found under fm_FT_WBS.cus
//
// DT - 17-Feb-06
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The modes
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//modes: see fm_testmodes.cus
/////////////////////////////////////////////////////
//Blocks
/////////////////////////////////////////////////////
// Switches comb and zero, block
block Switch_zero_comb_block_fm HIFI 3717 {
    string status = "ON" in ["ON","OFF"]; //Status: ON or OFF
}{
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_ON");
    delay(2);
}

//////////////////////////////////////////////////////////////////////
// Generic procedure to call a Configure_spectroscopy command
// for total power and slow chop observations
procedure ConfigureSpectroscopy {
    /* Integration time */
    int data_time = 4; // Integration time between two data readouts
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string chopmode = "chop" in ["chop","lchop","fs","hot-cold","tp"]; // Chop mode determining the modulation dead time
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used,channel windows}
}{
    // Get timing parameters
    {int,int,int,int,int,int,int,int,int,int} timing = ConfigureSpectroscopyParams(data_time,n_data,chopmode,band,lo_freq,backendreadoutparms);
    int n_wbs_start = timing{0};
    int r_hrs = timing{1};
    int n_wbs_integr = timing{2};
    int n_hrs_integr = timing{3};
    int del_hrs = timing{4};
    int del_wbs = timing{5};
    int t_acc_wbs = timing{6};
    int t_acc_hrs = timing{7};
    // Transfer mode
    {int,int,int,int,int[],int[],string} backendconfigure = ConfigSpectroscopyBackends(data_time,backendreadoutparms);
    int wbs_rshift = backendconfigure{0};
    int hrs_rshift = backendconfigure{1};
    int hrsh_sel = backendconfigure{2};
    int hrsv_sel = backendconfigure{3};
    int[] wbsh_par = backendconfigure{4};
    int[] wbsv_par = backendconfigure{5};
    string packing = backendconfigure{6};
    // Now call the command
    Hifi_HIFI_config_spectroscopy($BBID,n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,wbsh_par[0],wbsh_par[1],wbsh_par[2],wbsh_par[3],wbsh_par[4],wbsh_par[5],wbsh_par[6],wbsh_par[7],wbsv_par[0],wbsv_par[1],wbsv_par[2],wbsv_par[3],wbsv_par[4],wbsv_par[5],wbsv_par[6],wbsv_par[7],hrs_rshift,wbs_rshift,hrsh_sel,hrsv_sel,packing);
    //
    // No delay for a configuration command
}

// Switch HIFI to primary mode, mode
// This only switches the LO to normal mode
mode HifiManCmd_HIFI_standbyII_to_primary {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
    string chopper_loop = "OPEN" in ["OPEN","CLOSE"]; //chopper loop status
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    Mode_status_check_standby_II(laser_H,laser_V,chopper_loop,"up",prime_or_redundant);
    mois_comment("Set HIFI to Primary mode with " + laser_H + " switched on");
    //
    StartMode_block_ops();
    //Switch LO to nominal
    mois_step("Set LOU to normal mode");
    Set_LO_Nominal_block_ops();
    //
    StopMode_block_ops();
    Mode_status_check_primary(laser_H,laser_V,chopper_loop);
}

//////////////////////////////////////////////
// Testmodes for COP specific activities
// They are usually concatenation of 
// existing modules, here gathered for
// a simpler execution
//
// Note that it needs update of lastobsids
//
// DT - 24-01-08
//////////////////////////////////////////////
//HIFI-FCP-HC1: chopper health check#1
obs HifiEng_Chopper_FT1_COP {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Chopper_FT1_COP_proc_ops(prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Chopper_FT1_COP_proc_ops(prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// Interpolate differential total power load chop Allan time and exponent
double[] procedure InterpolateTpLChopAllan {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    bool subband = false; // 1GHz bandwith reference instead of full IF
}{
    // subband is not used yet
    double[] allan = CalibrationReader("loadchop_Allan",["tp_Allan_time","tp_Allan_exp","tp_binning_exp"],band,lo_freq);

    return allan;
}

//HIFI vector scan, block
//Check vector scan with some default parameters
block Vector_scan_block_fm HIFI 3627 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    drain2_v_start = drain2_safe;
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    //delay(1);
    //Execute vector scan 
    Hifi_HIFI_vector_scan($BBID);
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//Slow chop between sky and CBB, block
block Sky_Cold_fm_COP HIFI 3928 {
    string band = "1a";
    int integ_time = 4; //Total integration time for delay computation
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,etc
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast 
}{
    //Fetch respective chopper angles
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_M3","chop_cold"],band,0.0);
    double chop_M3 = result[0]{0};
    double chop_cold = result[1]{0};
    //
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"slowchop",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    HIFI_Spectr_slow_chop_proc_fm(chop_cold,chop_M3);
    Apply_Slow_Chop_delay(integ_time,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// Functional test with unpumped mixer, procedure
// This case assumes backend attenuator setting is done
procedure FT_unpumped_w_att_setting {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,etc
    int integ_time = 4; //Integration time
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //
    //Tune on high resistive bias
    //Get biases. No LO freq. given
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["bias_high_resistive_h","bias_high_resistive_v"],band,0.0);
    double bias_h = result_d[0]{0};
    double bias_v = result_d[1]{0};
    //Before applying these high biases, need to set magnets to 0
    Set_Magnet_current_block_fm(0.0,0.0);
    //
    Mixerbias_block_fm(bias_h,bias_v);
    //
    //Backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_config_block_fm(band);
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Reconfigure spectrometers integration after tuning
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //Measure IF noise
    IFcalibration(band,integ_time,backend);
    //Set magnet to zero and get IVcurve: only up to band 5 since band6-7 have no magnets
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        //At that stage, the baises and magnets have been set back to nominal values
        //IV curve with default parameters
        IVcurve_raw_fm(band);
        //Set magnet to zero and get IVcurve: only up to band 5 since band6-7 have no magnets
        IVcurve_with_zero_magnet_fm(band);
        //Heater
        Heater_fm(band);
        //Now sets back the magnet to nominal value
        //Set magnet to zero and get IVcurve: only up to band 5 since band6-7 have no magnets
        IVcurve_with_zero_magnet_fm(band);
    }
    //IVcurve after defluxing
    IVcurve_defluxed_fm(band);
}

//Chopper health check: step#1
procedure Chopper_FT1_COP_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Chopper health check: needs to start in open loop
    double lo_freq = 0.0;
    double chopper_voltage = 0.0;
    Init_MSA_ops("0","OPEN",lo_freq,chopper_voltage,"ON",prime_or_redundant);
    //Go to 2048 RAW
    Chopper_openloop_set_block_ops(0,prime_or_redundant);
    //Go to 2118 RAW
    Chopper_openloop_set_block_ops(1,prime_or_redundant);
    //Back to 2048 RAW
    Chopper_openloop_set_block_ops(0,prime_or_redundant);
    //
}

// HRS polar switch test - alternative scenario proposed by PD, block
procedure HRS_polar_switch_alternative_proc_fm {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    //some global settings 
    int integ_time = 4;
    string backend = "hrs";
    //First set bias to 5mV
    Mixerbias_block_fm(5.0,5.0);
    //Configure HRS with normal switches
    HRS_config_w_switch_block_fm(band,hrs_mode,["H","V"]);
    //tune and take spectrum
    HRS_tune_block_fm(band);
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
    //Set bias to 10 and 2 mV resp
    Mixerbias_block_fm(10.0,2.0);
    //tune and take spectrum
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
    //Swap switches
    HRS_config_w_switch_block_fm(band,hrs_mode,["V","H"]);
    //tune and take spectrum
    HRS_tune_block_fm(band);
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
}

// Automatic magnet tuning, block
// Also assumes backends are ready
// This is to be used in cold context
block Magnet_tuning_block_fm HIFI 3609 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b"]; // HIFI band
    double lo_freq = 522.0; //LO frequency
    string backend_code = "HRS" in ["WBS","HRS"]; //The backend to be used for tuning
    int tune_target_magnet = 40 in [10,85]; //Target WBS illumination percentage during magnet tuning
}{
    Start_block();
    //Set mixer bias to special bias for tuning
    {double,string}[] result = ConfigurationReader("name_confilmix",["bias4magn_h","bias4magn_v","norm_bias_h","norm_bias_v"],band,lo_freq);
    //For bands 1,2 and 5, we must substract 0.09mV to this value
    double bias4magnh = result[0]{0};
    double bias4magnv = result[1]{0};
    if(band == "1a" || band == "1b" || band == "2a" || band == "2b" || band == "5a" || band == "5b") {
        bias4magnh = bias4magnh - 0.09;
        bias4magnv = bias4magnv - 0.09;
    }
    Mixerbias(bias4magnh,bias4magnv);
    double normal_bias_h = result[2]{0};
    double normal_bias_v = result[3]{0};
    //
    //First set magnets to maximum because of hysteresis
    result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
    double magnetcurrentmax_H = result[0]{0};
    double magnetcurrentmax_V = result[1]{0};
    Set_Magnet_current_proc_fm(magnetcurrentmax_H,magnetcurrentmax_V);
    //
    //For band5, wait another 5 sec here
    if(band == "5a" || band == "5b") {
        delay(5);
    }
    //Fetch magnet tuning parameters
    //Middle of the scan
    result = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
    double h_mx_mg0 = result[0]{0};
    double v_mx_mg0 = result[1]{0};
    //
    result = ConfigurationReader("name_configmagtune",["nMagnet","stepT","mx_mg_span"],band,lo_freq);
    //
    //Tuning strategy: scan nMagnet points over -span/2 to +span/2% of nominal value
    //at the frequency of interest
    int nMagnet = iround(result[0]{0});
    double stepT = result[1]{0};
    double mx_mg_span = result[2]{0};
    double scan_range = mx_mg_span * max(h_mx_mg0,v_mx_mg0) / 100.0;
    double mx_mg_step = -1.0 * scan_range / double(nMagnet);
    //Starting scan values
    h_mx_mg0 = h_mx_mg0 - mx_mg_step * double(nMagnet) / 2.0;
    v_mx_mg0 = v_mx_mg0 - mx_mg_step * double(nMagnet) / 2.0;
    //
    //Set magnets to starting value to do backend tuning
    Set_Magnet_current_proc_fm(h_mx_mg0,v_mx_mg0);
    //
    //Tune attenuators of backends before magnet tuning
    ///The following is not yet done. Still take as input parameter
    //result = ConfigurationReader("name_configwbs",["tune_target_magnet"],band,lo_freq);
    //int tune_target_magnet = iround(result[0]{0});
    //
    //Perform tuning: check which backend shall be used
    int magtune_delay = 0;
    if(backend_code == "WBS") {
        Hifi_HIFI_Tune_WBS($BBID,tune_target_magnet);
        //Get delay
        result = ConfigurationReader("name_delays",["wbs_tune_delay"],band,0.0);
        delay(iround(result[0]{0}));
        //
        Hifi_HIFI_Tune_mxmgc_useWBS($BBID,stepT,nMagnet,h_mx_mg0,v_mx_mg0,mx_mg_step);
        //Compute delay
        magtune_delay = iceil(1.0 + 0.94 + double(nMagnet) * (stepT + 1.05)) + 1;
        //according to OBS 4.4: extra second added
    } else {
        Hifi_HIFI_Tune_HRS($BBID);
        //Get delay
        result = ConfigurationReader("name_delays",["hrs_tune_delay"],band,0.0);
        delay(iround(result[0]{0}));
        //
        Hifi_HIFI_Tune_mxmgc_useHRS($BBID,stepT,nMagnet,h_mx_mg0,v_mx_mg0,mx_mg_step);
        magtune_delay = iceil(1.0 + 0.072 + double(nMagnet) * (stepT + 0.132)) + 1;
        //according to OBS 4.4: extra second added
    }
    //
    delay(magtune_delay);
    //Set mixer bias back to nominal value at frequency of interest
    Mixerbias(normal_bias_h,normal_bias_v);
    //
}

//
// Diplexer scan very fast with IF power, block.
// Mixer current as function of diplexer current.
// Uses the new OBS TC allowing much faster scan.
block Scan_diplexer_IF_block_fm HIFI 3255 {
    string band = "3a"; // HIFI band
    double diplexer_current_min_h = -2.24; //minimum diplexer current H
    double diplexer_current_min_v = -2.24; //minimum diplexer current V
    double diplexer_current_step = 0.1; //maximum diplexer current V
    int n_steps = 100; //number of steps
    double stepTime = 0.1; //Step time in seconds
    double lo_freq = 807.0; //LO frequency  
}{
    //
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        double bias_max_h = result[0]{0};
        double bias_max_v = result[1]{0};
        //
        result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        double bias_normal_h = result[0]{0};
        double bias_normal_v = result[1]{0};
    }
    //Check how many TCs need to be sent
    int max_step = 20;
    int nloop = iceil(double(n_steps) / double(max_step));
    //Compute number of step for last iteration
    int last_n_steps = n_steps - (nloop - 1) * max_step;
    int dipscan_delay = 0;
    //Send command for HBB position
    Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_hot_ang");
    //
    //Preset to first value and wait 1sec (for possible overshoot): already done before HRS tuning
    //Set_Diplexer_current_proc_fm(diplexer_current_min_h,diplexer_current_min_v);
    //
    double diplexer_current_h = diplexer_current_min_h;
    double diplexer_current_v = diplexer_current_min_v;
    //
    for(int i = 1 .. nloop) {
        n_steps = max_step;
        if(i == nloop) {
            n_steps = last_n_steps;
        }
        diplexer_current_h = diplexer_current_min_h + double((i - 1) * max_step) * diplexer_current_step;
        diplexer_current_v = diplexer_current_min_v + double((i - 1) * max_step) * diplexer_current_step;
        //
        Hifi_HIFI_scan_diplexer_if($BBID,n_steps,stepTime,diplexer_current_h,diplexer_current_v,diplexer_current_step);
        //Compute delay
        dipscan_delay = iceil(1.0 + 0.042 + double(n_steps) * (stepTime + 0.2));
        //According to SPR-903
        delay(dipscan_delay + 1);
    }
    //In case of HEBs, we may have reached oscillation regime at this stage
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        //Exit from oscillation regime
        Mixerbias(bias_max_h,bias_max_v);
        Mixerbias(bias_normal_h,bias_normal_v);
    }
    //Send command for CBB position
    Chopper_Rotation_proc_fm(band,"chop_hot_ang","chop_cold_ang");
    //
    //Preset to first value and wait 1sec (for possible overshoot)
    Set_Diplexer_current_proc_fm(diplexer_current_min_h,diplexer_current_min_v);
    //
    diplexer_current_h = diplexer_current_min_h;
    diplexer_current_v = diplexer_current_min_v;
    //
    for(int j = 1 .. nloop) {
        n_steps = max_step;
        diplexer_current_h = diplexer_current_min_h + double((j - 1) * max_step) * diplexer_current_step;
        diplexer_current_v = diplexer_current_min_v + double((j - 1) * max_step) * diplexer_current_step;
        if(j == nloop) {
            n_steps = last_n_steps;
        }
        Hifi_HIFI_scan_diplexer_if($BBID,n_steps,stepTime,diplexer_current_h,diplexer_current_v,diplexer_current_step);
        //Compute delay
        dipscan_delay = iceil(1.0 + 0.042 + double(n_steps) * (stepTime + 0.2));
        //According to SPR-903
        delay(dipscan_delay + 1);
    }
    //In case of HEBs, we may have reached oscillation regime at this stage
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        //Exit from oscillation regime
        Mixerbias(bias_max_h,bias_max_v);
        Mixerbias(bias_normal_h,bias_normal_v);
    }
}

// Global fast chop spectroscopy for stability measurement, procedure
procedure Fast_chop_spectro_for_Stability_proc_fm {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integrations
    int integ_time = 8; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    double chop1 = 3.4; //First chopper position
    double chop2 = 4.7; //Second chopper position
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Compute data_time and n_switch using the wrapper
    int[] res = ConfigFastChop(integ_time,chop_phase,band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_int = res[2];
    int n_data = n;
    //For stability measurement, the number of loop is a user input
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS.
    // The deadtimes output is not used at ILT level.
    {{double,double,double},{int,int}} pars = ConfigSpectroscopyFastChop(chop_phase,n_int,n_data,band,0.0,backendreadoutparms);
    int[] final_res = [res[0],res[1],pars{1}{0},pars{1}{1}];
    int n_wbs_start = n_data;
    int n_wbs1 = final_res[2];
    int n_hrs_trans = final_res[3];
    //Compute data-rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time / 2);
    double[] rates = dataparms{1};
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //Now start the long integration
    HIFI_Spectr_fast_chop_proc_fm(chop1,chop2,n_wbs1,n_hrs_trans);
    //Apply delays
    int total_time = iceil(chop_phase * double(n_wbs_start * n_wbs1));
    Apply_Fast_Chop_delay(total_time,n_wbs_start,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// Noise ratio from an asymmetric double difference observation
double procedure DoubleDifferenceNoiseRatio {
    double x = 0.1; // value for integration time relative to Allan time
    double[] parameters = [1.0,1.0,0.8,0.8,0.05,0.3,2.5,5.0,2.5]; // Parameters: ratio of integration times, ratio of effective resolutions, delay in phase1, in phase 2, between phases relative to Allan time, drift exponents 
}{
    {double,double} noisevalues = DoubleDifferenceNoiseValues(x,parameters);
    double y = noisevalues{1} / noisevalues{0};

    return y;
}

////////////////////////////////////
// OTF frequency switch observing mode
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcFSwitchOTF {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    bool refSelected = true; // Dummy parameter required by HSPOT
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints = 10 in [1,720]; // Number of data dumps per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Mapping - OTF Map Frequency Switch Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,n_linesperscan,0,0,n_cycles,load_interval});
    // Auxiliary routine for API parameter correction
    {double,double,int} mapused = ValidMapSize(band,lo_freq,lineDistance,nlines,stepsize,npoints,2 * data_time * n_switch_on);
    double line_used = mapused{0};
    double scanvelocity = mapused{1};
    int npoints_used = mapused{2};
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int} pre_timing = OTFFSwitch_pre_timing(nlines,npoints_used,band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_linesperscan,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,double,double,int,int,int,int,int} tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,pre_timing);
    // Dummy call to spacecraft command
    int[] telescopetimes = line_scan_with_off_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int},double,double} post_timing = OTFmap_post_timing(pre_timing,telescopetimes,data_time,n_linesperscan,n_cycles,load_interval);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,post_timing{1});
    // Call telescope command
    telescopetimes = line_scan_with_off_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int n_pp = post_timing{1}{0};
    int n_scans = post_timing{1}{1};
    int off_inttime = post_timing{1}{2};
    int loadlength = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{5};
    double tscan = post_timing{2};
    double tdead = post_timing{3};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        OTFFSwitch_commanding(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,npoints_used * n_switch_on,n_switch_off,nlines * n_cycles,n_linesperscan,n_loadinterval,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = OTFDoubleChop_deadtimes("fs",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_linesperscan,n_pp,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = OTFFSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,nlines,data_time,n_switch_on,n_linesperscan,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    OTFDoubleChop_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints_used,n_switch_on,n_switch_off,n_scans,n_cycles,true,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

///////////////////////////////////////////////////////////////
//// OBSOLETE MODULES  ///////////////////////////////////////
//////////////////////////////////////////////////////////////
/////////////OBSOLETE: THIS IS NOT USED ANYMORE//////////////////////////
//Procedure checking whether the requested integration
//time is compliant with the allowed packet/datarate
//in Total power spectroscopy context
bool procedure Check_Total_Power_datarate {
    int n_wbs_start = 1; //Nb of frames
    int r_hrs = 1; //Nb of HRS readout per WBS readout
    int n_wbs_integr = 1; //Number of wbs readout packetized per WBS frame
    int n_hrs_integr = 1; //Number of hrs readout packetized per HRS frame
    int del_hrs = 5; //Delay before starting HRS integration
    int del_wbs = 5; //Delay before starting WBS integration
    int t_acc_wbs = 4005; //Duration of WBS frame 
    int t_acc_hrs = 1950; //Duration of HRS frame
    int wbsh_offset1 = 0;
    int wbsh_width1 = 2048;
    int wbsh_offset2 = 2048;
    int wbsh_width2 = 2048;
    int wbsh_offset3 = 4096;
    int wbsh_width3 = 2048;
    int wbsh_offset4 = 6144;
    int wbsh_width4 = 2048;
    int wbsv_offset1 = 0;
    int wbsv_width1 = 2048;
    int wbsv_offset2 = 2048;
    int wbsv_width2 = 2048;
    int wbsv_offset3 = 4096;
    int wbsv_width3 = 2048;
    int wbsv_offset4 = 6144;
    int wbsv_width4 = 2048;
    int hrs_rshift = 0; //HRS bit shift
    int wbs_rshift = 0; //WBS bit shift
    int hrsh_sel = 255; //HRS-H band selection
    int hrsv_sel = 255; //HRS-V band selection
    string wbs_packing = "24_bits_format";
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    error("Procedure Check_Total_Power_datarate is not used anymore.");

    return false;
}

// Add two vectors defined as tuples
{double,double} procedure AddVectors {
    {double,double} vector1 = {1.0,1.0};
    {double,double} vector2 = {1.0,1.0};
}{

    return {vector1{0} + vector2{0},vector1{1} + vector2{1}};
}

//HIFI vector scan, procedure
//Check vector scan with some default parameters
procedure Vector_scan_proc_1a {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 570.0; //LO frequency
}{
    error("This module is obsolete: use Vector_scan_proc instead");
}

// Check of Bragg cell heating using internal loads, block
block FT_WBS_BraggCell_HotCold_fm HIFI 3712 {
    string band = "1a"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON 
    int[] att_h = [7,7,7,7,12]; //User input att. for optimum level H-polar
    int[] att_v = [7,7,7,7,12]; //User input att. for optimum level H-polar
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //Look at hot source: force a 2-step rotation
    Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_hot_ang");
    //
    //Test continuum signal response
    //1. Set WBS attenuators to work at nominal level 
    //for the current input (minimum attenuation without saturation)
    //It practice the CUS cannot read back the optimum settings from 
    //a tuning...instead we consider they are input
    //Must be done manually...
    //
    {double,string}[] result = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4","hwh_att_band3","hwh_att_band2","hwh_att_band1","hwh_att_in"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result[2]{0});
    string hwh_latchup_s = result[3]{1};
    int hwh_att_band4 = att_h[3];
    //iround(result[4]{0});
    int hwh_att_band3 = att_h[2];
    //iround(result[5]{0});
    int hwh_att_band2 = att_h[1];
    //iround(result[6]{0});
    int hwh_att_band1 = att_h[0];
    //iround(result[7]{0});
    int hwh_att_in = att_h[4];
    //iround(result[8]{0});
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //
    result = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4","hwv_att_band3","hwv_att_band2","hwv_att_band1","hwv_att_in"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result[2]{0});
    string hwv_latchup_s = result[3]{1};
    int hwv_att_band4 = att_v[3];
    //iround(result[4]{0});
    int hwv_att_band3 = att_v[2];
    //iround(result[5]{0});
    int hwv_att_band2 = att_v[1];
    //iround(result[6]{0});
    int hwv_att_band1 = att_v[0];
    //iround(result[7]{0});
    int hwv_att_in = att_v[4];
    //iround(result[8]{0});
    //
    //2. Configure spectroscopy and do integration: total of 100s with 4s integration
    Total_power_spectro_for_Stability_proc_fm(band,25,4,backend,["wb1","wb1"]);
    //
    //Look at the cold source
    Chopper_Rotation_proc_fm(band,"chop_hot_ang","chop_cold_ang");
    //
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Integrate with the WBS
    Total_power_spectro_for_Stability_proc_fm(band,25,4,backend,["wb1","wb1"]);
    //
    //Look at the hot source
    Chopper_Rotation_proc_fm(band,"chop_cold_ang","chop_hot_ang");
    //
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Integrate with the WBS
    Total_power_spectro_for_Stability_proc_fm(band,25,4,backend,["wb1","wb1"]);
    //
    //Look at the cold source
    Chopper_Rotation_proc_fm(band,"chop_hot_ang","chop_cold_ang");
    //
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Integrate with the WBS
    Total_power_spectro_for_Stability_proc_fm(band,25,4,backend,["wb1","wb1"]);
    //
    //Settling time of COMB
    //We have to set attenuators to values different from max.
    //12,3,3,3,3: info from Oliver Sibertz. This may change for FM
    //Initial configuration
    //H-Polarization
    result = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4_comb","hwh_att_band3_comb","hwh_att_band2_comb","hwh_att_band1_comb","hwh_att_in_comb"],band,0.0);
    hwh_laser1_s = "OFF";
    hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    hwh_heater = iround(result[2]{0});
    hwh_latchup_s = result[3]{1};
    hwh_att_band4 = iround(result[4]{0});
    hwh_att_band3 = iround(result[5]{0});
    hwh_att_band2 = iround(result[6]{0});
    hwh_att_band1 = iround(result[7]{0});
    hwh_att_in = iround(result[8]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4_comb","hwv_att_band3_comb","hwv_att_band2_comb","hwv_att_band1_comb","hwv_att_in_comb"],band,0.0);
    hwv_laser1_s = "OFF";
    hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    hwv_heater = iround(result[2]{0});
    hwv_latchup_s = result[3]{1};
    hwv_att_band4 = iround(result[4]{0});
    hwv_att_band3 = iround(result[5]{0});
    hwv_att_band2 = iround(result[6]{0});
    hwv_att_band1 = iround(result[7]{0});
    hwv_att_in = iround(result[8]{0});
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Set Zero and COMB ON
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_ON");
    delay(2);
    //
    //Integrate with the WBS
    Total_power_spectro_for_Stability_proc_fm(band,25,4,backend,["wb1","wb1"]);
    //
    //Still TBD here: [Perform comb measurements for different Bragg cell heat levels]
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_OFF");
    delay(1);
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_OFF");
    delay(1);
    //Configure Spectroscopy
    //Configure_Spectrometer_proc_fm(band,4,["wb1","wb1"]);
}

//General DC health check, procedure
//All inputs are taken from look-up tables using safe values
procedure LCU_DC_health_check_proc_fm {
    string band = "1a" in ["ALL","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int operation_delay = 60; //When ALL is selected, Waiting delay between two measurements on a band (e.g. to change connector)
}{
    //Array of names
    string[] band_array = ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"];
    double hl_PL_C = 0.0;
    double hl_M1_V = 0.0;
    double hl_M2_V = 0.0;
    double hl_M3_V = 0.0;
    double hl_Gate1_V = 0.0;
    double hl_Gate2_V = 0.0;
    double hl_Drain1_V = 0.0;
    string hl_Curlim1 = "1.5";
    double hl_Drain2_V = 0.0;
    string hl_Curlim2 = "1.5";
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["pl_c","m1_v","m2_v","m3_v","g1_v","g2_v","d1_v","d2_v"],"1a",1.0);
    //Case of all bands done
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
    }
    //
    string band_loop = "1a";
    //
    if(band == "ALL") {
        //loop on bands
        for(int i = 1 .. 14) {
            //Readout safe values
            cresult = CalibrationReader("name_lcu_safe_values",["pl_c","m1_v","m2_v","m3_v","g1_v","g2_v","d1_v","d2_v"],band_array[i - 1],double(i));
            hl_PL_C = cresult[0];
            hl_M1_V = cresult[1];
            hl_M2_V = cresult[2];
            hl_M3_V = cresult[3];
            hl_Gate1_V = cresult[4];
            hl_Gate2_V = cresult[5];
            hl_Drain1_V = cresult[6];
            hl_Drain2_V = cresult[7];
            //
            {double,string}[] result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band_array[i - 1],0.0);
            hl_Curlim1 = result[0]{1};
            hl_Curlim2 = result[1]{1};
            //
            LCU_DC_health_check_block_fm(band_array[i - 1],hl_PL_C,hl_M1_V,hl_M2_V,hl_M3_V,hl_Gate1_V,hl_Gate2_V,hl_Drain1_V,hl_Curlim1,hl_Drain2_V,hl_Curlim2);
            //
            delay(operation_delay);
        }
    } else {
        //Only one band measured
        //Readout safe values
        cresult = CalibrationReader("name_lcu_safe_values",["pl_c","m1_v","m2_v","m3_v","g1_v","g2_v","d1_v","d2_v"],band,0.0);
        hl_PL_C = cresult[0];
        hl_M1_V = cresult[1];
        hl_M2_V = cresult[2];
        hl_M3_V = cresult[3];
        hl_Gate1_V = cresult[4];
        hl_Gate2_V = cresult[5];
        hl_Drain1_V = cresult[6];
        hl_Drain2_V = cresult[7];
        //
        result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,0.0);
        hl_Curlim1 = result[0]{1};
        hl_Curlim2 = result[1]{1};
        //
        LCU_DC_health_check_block_fm(band,hl_PL_C,hl_M1_V,hl_M2_V,hl_M3_V,hl_Gate1_V,hl_Gate2_V,hl_Drain1_V,hl_Curlim1,hl_Drain2_V,hl_Curlim2);
        //
        delay(operation_delay);
    }
    //
}

// First part of WBS FM functional test, block
// Check temperature modification when setting the heaters
block FT_WBS_heater_fm HIFI 3700 {
    string band = "1a"; // HIFI band
}{
    //Start_block(); 
    //Time to wait after each heater powering
    int heater_deadtime = 600;
    //in sec.
    //Initial configuration
    //H-Polarization
    //
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    int hwh_heater = 0;
    //000
    string hwh_latchup_s = "Level1";
    int hwh_att_band4 = 7;
    int hwh_att_band3 = 7;
    int hwh_att_band2 = 7;
    int hwh_att_band1 = 7;
    int hwh_att_in = 15;
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    delay(1);
    //
    //V-Polarization
    //
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    int hwv_heater = 0;
    //000
    string hwv_latchup_s = "Level1";
    int hwv_att_band4 = 7;
    int hwv_att_band3 = 7;
    int hwv_att_band2 = 7;
    int hwv_att_band1 = 7;
    int hwv_att_in = 15;
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(1);
    //Start switching heaters: switch on first heater
    hwh_heater = 1;
    //001
    hwh_heater = 1;
    //001
    //
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(heater_deadtime);
    //Switch on second heater
    hwh_heater = 3;
    //011
    hwh_heater = 3;
    //011
    //
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(heater_deadtime);
    //Switch on second heater
    hwh_heater = 7;
    //111
    hwh_heater = 7;
    //111
    //
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(heater_deadtime);
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CUS scripts for HIFI global operations.
// It includes:
//    - SFT
//    - FT
//    - VSPT
//    - System and IF noise measurements
//    - Standing wave measurements
//    - Standing wave + stability 
//
// DT - 23-May-06
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The modes
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// See fm_testmodes.cus
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The procedures
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Fast-readout of mixer currents, block
block Fast_Imix_block_fm HIFI 3795 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string polarization = "B" in ["H","V","B"]; //mixer to be sampled: H, V or B. If B, they are done successively
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50];
    int samplesAfter = 1000 in [0,1000];
}{
    //
    Start_block();
    //
    if(polarization == "H" || polarization == "B") {
        Hifi_HIFI_MXJNC_H_scan_fast(milliSecSample,samplesBefore,samplesAfter);
        // delay calculation
        int nb_HK = 1;
        //For this TC, the 2 last HK fields are blanked out
        int millisecondsUsed = 1000 + 10 + milliSecSample * nb_HK * (samplesBefore + samplesAfter);
        delay(iceil(0.0010 * double(millisecondsUsed)) + 1);
    }
    //
    if(polarization == "V" || polarization == "B") {
        Hifi_HIFI_MXJNC_V_scan_fast(milliSecSample,samplesBefore,samplesAfter);
        // delay calculation
        nb_HK = 1;
        //For this TC, the 2 last HK fields are blanked out
        millisecondsUsed = 1000 + 10 + milliSecSample * nb_HK * (samplesBefore + samplesAfter);
        delay(iceil(0.0010 * double(millisecondsUsed)) + 1);
    }
}

//HIFI LO tuning for FSW cases, block
//Settings for both frequencies need to be common
//and are passed through lo_freq_setting
//Target current is read from look-up table
block LO_tuning_FSW_block_fm HIFI 3676 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency at which to set LSU
    double lo_freq_setting = 501.0; //LO frequency at which to take the settings
    bool fswstorage = true; // whether FSW register shall be stored
}{
    //Clear potential failure mode
    if(fswstorage) {
        Set_LO_Nominal_proc_fm();
    } else {
        delay(1);
        //to keep timing in OD29/OD30
    }
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    string mixer_polarization = result[0]{1};
    //
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq_setting);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scans
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double middle_d2 = result[0]{0};
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    //
    //delay(5);	//to settle at this value
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

// Diplexer scan, very fast with IF power, procedure
// Uses the fast OBS TC
procedure Diplexer_scan_IF_proc {
    string band = "3a" in ["0","3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI band
    double diplexer_current_min_h = -2.24; //starting diplexer current H
    double diplexer_current_min_v = -2.24; //starting diplexer current V
    double diplexer_current_step = 2.24; //Common diplexer current step
    int n_steps = 100; //number of steps
    double stepTime = 0.1; //Step time in seconds: GRANULARITY IS 0.1sec!!!!
    double lo_freq = 807.0; //LO frequency
}{
    //
    //In case of band 6 or 7, use special biases
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v","bias_max_h","bias_max_v"],band,lo_freq);
        //First go to 4mV
        Mixerbias_block_fm(result[2]{0},result[3]{0});
        //Then to 3mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //
    //Fetch diplexer settings
    double[] result_dip = Get_Diplexer_setting(band,lo_freq);
    double diplex_H = result_dip[0];
    double diplex_V = result_dip[1];
    //
    //Set diplexers to the starting value to tune HRS
    Set_Diplexer_current_block_fm(diplexer_current_min_h,diplexer_current_min_v);
    //
    HRS_tune_block_fm(band);
    //
    //Perform scan
    Scan_diplexer_IF_block_fm(band,diplexer_current_min_h,diplexer_current_min_h,diplexer_current_step,n_steps,stepTime,lo_freq);
    //
    //Get back to optimal settings
    Set_Diplexer_current_block_fm(diplex_H,diplex_V);
    //
    //In case of band 6 or 7,go back to nominal values
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        //First go to 4mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
        //Then to nominal
        result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //
}

//Upload of LCU memory patches
//Prime/Redundant is handled with the CUS table
//Required as separate flight procedure as total number of command parameters
//is limited to 999
mode HifiManCmd_upload_LCU_patches_flight_ops {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string section = "P" in ["P","R"];
}{
    mois_comment("This procedure MUST be performed before the table upload series");
    mois_comment("Start LCU memory patch upload");
    mois_comment("Verify that the expected checksum has been provided by the HIFI representative within the associated TPF");
    mois_tmcheck("Verify that parameter HL_Mode_S is set to standby.");
    StartMode_block_ops();
    mois_step("Perform memory patch upload");
    LcuMemoryPatchUpload_ops(section);
    StopMode_block_ops();
}

{string,double,double}[] procedure HifiPointModeFastDBSSequencerInit {
    string modeName = "dbs";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get the drift parameters to compute the drift noise
    {double,double} phaselengths = DBSPhaseLengths(band,lo_freq,effResolution,continuumDetection,oneGHzReference);
    // Compute derived quantities
    // Top down approach here
    int main_phase = iceil(phaselengths{0});
    int data_time_guess = 40;
    int n_switch_on_guess = main_phase / data_time_guess;
    if(n_switch_on_guess < 2) {
        n_switch_on_guess = 2;
        data_time_guess = main_phase / n_switch_on_guess;
    }
    // Check with data rate
    {int,double[]} dataparms = DataTaking(backendreadoutparms,8);
    int datalimit = 2 * dataparms{0};
    if(data_time_guess < datalimit) {
        data_time_guess = datalimit;
        n_switch_on_guess = 1;
    }
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // Chop phase length
    double phase_min = min(max(phaselengths{1},0.15),1.5);
    int n_int_on_guess = ifloor(double(data_time_guess) / (2.0 * phase_min));
    int n_int_on_range = -n_int_on_guess / 2;
    if(n_int_on_range == 0) {
        n_int_on_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_int_on",double(n_int_on_guess),double(n_int_on_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)}];

    return retvalues;
}

//////////////////////////////////////////////////////////
// New building blocks
// Slow chop integration at source position OFF-ON-ON-OFF...
block HIFIHalfChopOnIntegration HIFI 6051 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_slow_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_M3","chop_M3right"],rates);
}

// First part of FPSS FM functional test, block
// Check that IF amplification is effective
block FT_FPU_check_IF_fm HIFI 3800 {
    string band = "1a";
    int integ_time = 4; //Integation time in seconds
    string context = "warm" in ["warm","cold"]; //Test context: warm or cold
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //At that stage all IF are ON. Take a spectrum
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //
    //Switch OFF FIF
    //Get parameters
    {double,string}[] result_h = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    if(context == "warm") {
        result_h = ConfigurationReaderWarm("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    }
    //
    int band_nb = iround(result_h[0]{0});
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = 0.075;
    double curr_H_FIF_1 = 0.5;
    double volt_H_FIF_2 = 0.075;
    double curr_H_FIF_2 = 0.5;
    //
    double volt_H_SIF_1 = result_h[5]{0};
    double curr_H_SIF_1 = result_h[6]{0};
    double volt_H_SIF_2 = result_h[7]{0};
    double curr_H_SIF_2 = result_h[8]{0};
    double volt_H_SIF_3 = result_h[9]{0};
    double curr_H_SIF_3 = result_h[10]{0};
    // 
    {double,string}[] result_v = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    if(context == "warm") {
        result_v = ConfigurationReaderWarm("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    }
    //
    //
    double volt_V_FIF_1 = 0.075;
    double curr_V_FIF_1 = 0.5;
    double volt_V_FIF_2 = 0.075;
    double curr_V_FIF_2 = 0.5;
    //
    double volt_V_SIF_1 = result_v[4]{0};
    double curr_V_SIF_1 = result_v[5]{0};
    double volt_V_SIF_2 = result_v[6]{0};
    double curr_V_SIF_2 = result_v[7]{0};
    double volt_V_SIF_3 = result_v[8]{0};
    double curr_V_SIF_3 = result_v[9]{0};
    //
    string chop_sine_s = "ON";
    string chop_loop = "CLOSE";
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,0.0);
    if(context == "warm") {
        result = ConfigurationReaderWarm("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,0.0);
    }
    //
    int chop_G1 = iround(result[0]{0});
    int chop_G2 = iround(result[1]{0});
    int chop_Z1 = iround(result[2]{0});
    int chop_Z2 = iround(result[3]{0});
    int chop_P2 = iround(result[4]{0});
    //
    //
    //  
    double calibcurrent = result[7]{0};
    //
    double bias_H = 0.0;
    double magnetcurrent_H = 0.0;
    double diplex_H = 0.0;
    double bias_V = 0.0;
    double magnetcurrent_V = 0.0;
    double diplex_V = 0.0;
    double chopper = 0.0;
    //
    //
    chopper = Check_Chopper_Prime_Redundant(chopper);
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result[0]{0});
    delay(config_fpu_delay);
    //
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //
    //Switch OFF SIF
    //
    volt_H_SIF_1 = 0.075;
    curr_H_SIF_1 = 0.5;
    volt_H_SIF_2 = 0.075;
    curr_H_SIF_2 = 0.5;
    volt_H_SIF_3 = 0.075;
    curr_H_SIF_3 = 0.5;
    // 
    volt_V_SIF_1 = 0.075;
    curr_V_SIF_1 = 0.5;
    volt_V_SIF_2 = 0.075;
    curr_V_SIF_2 = 0.5;
    volt_V_SIF_3 = 0.075;
    curr_V_SIF_3 = 0.5;
    //
    chopper = Check_Chopper_Prime_Redundant(chopper);
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    delay(config_fpu_delay);
    //
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //
}

{int,double,double,double,double,double} obs HifiPointModeLoadChop {
    string modeName = "load";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half load-sky-sky-load cycles on ON
    int n_switch_off = 2 in [1,900]; // number of half load-sky-sky-load cycles on OFF
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF calibration cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Single Point - Load Chop Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,0,0,0,n_cycles,load_interval});
    // position switch
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} pre_timing_ps = LoadChop_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_cycles,load_interval,docommands);
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar_ps = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,pre_timing_ps,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar_ps{0},tpar_ps{1},tpar_ps{2},tpar_ps{3},tpar_ps{4},tpar_ps{5},tpar_ps{6},tpar_ps{7},tpar_ps{8},tpar_ps{9},tpar_ps{10},tpar_ps{11},tpar_ps{12},tpar_ps{13},tpar_ps{14},tpar_ps{15},tpar_ps{16},tpar_ps{17},tpar_ps{18},true);
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},int,bool,double,double} post_timing_ps = DoubleChop_post_timing(pre_timing_ps,telescopetimes,n_cycles);
    // Now the actual observation starts
    // Prepare telescope command
    tpar_ps = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,post_timing_ps{1},n_cycles);
    // Call telescope command 
    telescopetimes = nodding_pointing(true,tpar_ps{0},tpar_ps{1},tpar_ps{2},tpar_ps{3},tpar_ps{4},tpar_ps{5},tpar_ps{6},tpar_ps{7},tpar_ps{8},tpar_ps{9},tpar_ps{10},tpar_ps{11},tpar_ps{12},tpar_ps{13},tpar_ps{14},tpar_ps{15},tpar_ps{16},tpar_ps{17},tpar_ps{18},true);
    // Consistency check
    int totaltime = post_timing_ps{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    //////////////////////////////////////////////////////////////////////
    int on_inttime = post_timing_ps{1}{0};
    int off_inttime = post_timing_ps{1}{1};
    int on_pointing = post_timing_ps{1}{2};
    int off_pointing = post_timing_ps{1}{3};
    int loadlength = post_timing_ps{1}{4};
    int n_loadinterval = post_timing_ps{1}{7};
    int n_per_on = post_timing_ps{1}{8};
    int n_per_off = post_timing_ps{1}{9};
    int n_load_on = post_timing_ps{1}{10};
    int n_load_off = post_timing_ps{1}{11};
    bool end_load_on = post_timing_ps{1}{12};
    bool end_load_off = post_timing_ps{1}{13};
    int initshiftlength = post_timing_ps{2};
    bool final_load = post_timing_ps{3};
    double tscan = post_timing_ps{4};
    double tdead = post_timing_ps{5};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    //////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        LoadChop_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_per_on,n_per_off,n_loadinterval,n_load_on,n_load_off,end_load_on,end_load_off,final_load,startobs,telescopetimes,loadlength,initshiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = DoubleChop_deadtimes("lchop",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_per_on,n_per_off,n_load_on,n_load_off,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = LoadChop_noisecomputer(band,lo_freq,effResolution,oneGHzReference,on_inttime,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    DoubleChop_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,n_per_on * (n_load_on + 1),n_per_off * (n_load_off + 1),false,tscan,on_pointing,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Horizontal transitions between open loop and closed loop contexts
// Can be either direction - This will only switch the chopper loop
// between open and closed.
mode HifiManCmd_HIFI_OL_from_to_CL {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string chopper_loop = "OPEN" in ["OPEN","CLOSE"]; //chopper loop status to be set
    string instrument_mode = "StandbyI" in ["StandbyI","StandbyII","Primary"]; //Instrument mode applying to the switch
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Preliminary check depending on the mode
    if(instrument_mode == "StandbyI") {
        mois_tmcheck("Check that parameters HWH_Laser1_S, HWH_Laser2_S, HWV_Laser1_S and HWV_Laser2_S are all OFF");
    }
    if(instrument_mode == "StandbyII") {
        //Nothing is made about the lasers.
        mois_tmcheck("Check that parameter HL_MODE_S is standby");
        mois_tmcheck("Check that parameter HL_Channel_S is Off");
    }
    if(instrument_mode == "Primary") {
        mois_tmcheck("Check that parameter HL_MODE_S is normal");
        mois_tmcheck("Check that parameter HL_Channel_S is Off");
    }
    //
    string chopper_start_loop = "CLOSE";
    if(chopper_loop == "CLOSE") {
        chopper_start_loop = "OPEN";
    }
    mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to " + chopper_start_loop);
    //Standby should always correspond to band0, lofreq=0
    string band = "0";
    double lo_freq = 0.0;
    mois_comment("Set HIFI chopper loop to " + chopper_loop + " in " + instrument_mode + " mode.");
    StartMode_block_ops();
    //Chopper loop status change
    mois_step("Switch chopper loop");
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],band,lo_freq);
    if(chopper_loop == "OPEN") {
        result = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    //HBB heater status depends on mode
    string hbb_status = "ON";
    if(instrument_mode == "StandbyI") {
        hbb_status = "ON";
    }
    Init_MSA_ops("0",chopper_loop,0.0,result[0]{0},hbb_status,prime_or_redundant);
    //
    StopMode_block_ops();
    mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to " + chopper_loop);
    mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to " + result[0]{0});
}

// Change the LO frequency to a new setting, keep backend settings
procedure HIFITuneFreq {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; //LO frequency
    bool newsetting = true; // whether LSU/LOU parameters are new
    string target_name = "sscan_normal"; // Name of target level
}{
    //
    //LO power tuning: could use either H or V polar
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    double x = result[0]{0};
    string tuningbackend = "H";
    if(iround(x) == 2) {
        tuningbackend = "V";
    } else {
        tuningbackend = "H";
    }
    //LO frequency tuning, and store in FSW register
    LO_tuning_block_aot(band,lo_freq / 1000.0,lo_freq / 1000.0,tuningbackend,newsetting,newsetting,false);
    //Spectrometer attenuator tuning - on the sky or cold load
    if(target_name != "") {
        WBS_attenuators_block(band,lo_freq / 1000.0,target_name,true);
    }
}

//Set LCU back to standby status without setting any particular LO band, block
//LCU is only set to standby if the band has been switched off
block LCU_standby_block_ops HIFI 7629 {
}{
    //
    {double,string}[] result = ConfigurationReader("name_delays",["stdby_delay"],"0",0.0);
    int stdby_delay = iround(result[0]{0});
    //
    //Set in standby mode
    Hifi_HIFI_HL_Standby($BBID);
    delay(stdby_delay);
    //Will be done at end of procedure during instrument mode status check
    //mois_tmcheck("Check that parameter HL_MODE_S is standby");
}

// Initialisation of FPU, block with both MSA in use
// It is for cold context !
// Note that is will use old magnet settings (prior to SCR-2372)
block Init_MSA_ops HIFI 7200 {
    string band = "1a"; // HIFI band
    string chop_loop = "CLOSE";
    double lo_freq = 500.0; //LO frequency
    double chopper = 0.0; //prime or redundant chopper voltage
    string hbb_heater = "ON" in ["ON","OFF"]; //hot source on/off
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //  
    double calibcurrent = result_d[7]{0};
    if(hbb_heater == "ON") {
        result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,0.0);
        calibcurrent = result_d[0]{0};
    }
    //
    //
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6 and 7
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range_COP(chopper,prime_or_redundant);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    if(prime_or_redundant == "Prime") {
        Hifi_HIFI_P_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    } else {
        Hifi_HIFI_R_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    }
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //In case of band 6 or 7, bias have been set to 6mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    //Magnet are so far at maximum value. Now set to nominal
    //For Init_MSA_ops, we use a table gathering the old settings - prior to SCR-2372
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        string tabmgn = "config_mix_FT.config";
        double norm_magn_h = dlookup(tabmgn,"" + band_nb,"norm_magn_h");
        double norm_magn_v = dlookup(tabmgn,"" + band_nb,"norm_magn_v");
        Hifi_HIFI_CH1_MX_MG_C($BBID,norm_magn_h);
        Hifi_HIFI_CV1_MX_MG_C($BBID,norm_magn_v);
        delay(1);
    }
    //
    Hifi_HIFI_non_periodic_hk_FCU();
}

int block HIFI_Calibrate_hot_cold HIFI 6005 {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    int data_time = 4; // time between subsequent data readouts
    int n_data = 2; // Integration time counter
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
    bool staycal = false; // whether we should stay at the hot load at the end
}{
    // data rate and read-out time
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int readout = dataparms{0};
    // send the configure spectroscopy command to configure the measurement
    // returned dead times not needed here
    ConfigureSpectroscopy(data_time,n_data,"hot-cold",band,lo_freq,backendreadoutparms);
    HIFI_Spectr_slow_chop_proc_aot(data_time,n_data / 2,band,lo_freq,["chop_hot","chop_cold"],dataparms{1});
    if(!staycal) {
        // Emit NOOP command to have the chopper rotation in second bus slot
        Hifi_HIFI_noop();
        // Move chopper back to the sky
        RotateChopper(band,lo_freq,"chop_M3");
    }
    // delay required at the end
    int sdelay = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // have clean bus timing for next spectroscopy block
    delay(sdelay);

    return readout;
}

// get backend bandwidth coverage (HRS only)
double procedure GetBackendBandwidth {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    int res_mode = 0; // coding for the backend resolution mode
}{
    if(res_mode < 0 || res_mode > 3) {
        double[] resol = CalibrationReader("backendresolution",["wbs_bandwidth"],band,lo_freq);
    }
    if(res_mode == 0) {
        resol = CalibrationReader("backendresolution",["hrs_high_bandwidth"],band,lo_freq);
    }
    if(res_mode == 1) {
        resol = CalibrationReader("backendresolution",["hrs_normal_bandwidth"],band,lo_freq);
    }
    if(res_mode == 2) {
        resol = CalibrationReader("backendresolution",["hrs_low_bandwidth"],band,lo_freq);
    }
    if(res_mode == 3) {
        resol = CalibrationReader("backendresolution",["hrs_wide_bandwidth"],band,lo_freq);
    }

    return resol[0];
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the peakup mode
procedure Peakup_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size
    int n_int = 1; // number of readouts
    double eff_resolution = 1.0; // Minimum  goal resolution in MHz
    double stepsize = 0.0050; // Distance between subsequent points in the raster line
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,10,10,29,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
}{
    // Auxiliary variables
    bool isWbs = wbs1{0} || wbs2{0};
    // Whether to use WBS
    bool isH = wbs1{0} || hrs1{0};
    // Whether to use H polarization 
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Different numbering in telescope command and peakup
    // Numbering starts from -Z,-Y, and proceeds first towards +Z
    int[] pointtable = [1,2,3,6,5,4,7,8,9];
    // Get all values from the telescope section  
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Initialization
            HIFIInitObs();
            TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            HIFISetHK("normal",false);
            // First load measurement
            LoadMeasurement(band,lo_freq,eff_resolution,data_time,backendreadoutparms);
            HifiPeakupConfigure(data_time,n_int,isH,band,lo_freq,stepsize,backendreadoutparms);
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            int pointnumber = pointtable[state[2] - 1];
            // In raster - actual measurement
            HIFIPeakupIntegration(data_time,n_int,isWbs,isH,pointnumber,band,lo_freq,rates);
        }
        // Final state
        if(state[0] == 5) {
            delay(readoutdead);
            // Perform AOCS correction
            HifiPeakupCorrection();
            HIFICloseObs();
        }
    }
}

/////////////////////////////////////////////////////////////////
// Procedure to call ConfigSpectroscopy with a single command
int[] procedure ConfigSlowChop {
    int observing_time = 8; // Integration time
    string chopmode = "chop" in ["chop","lchop","fs","hot-cold","tp","chopcal"]; // Chop mode determining the modulation dead time
    string band = "1a"; // HIFI band
    double lo_freq = 522000.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1 {used,resolution,subbands used}, HRS2 , WBS1 {used, channel windows}, WBS2 
}{
    // split integration time
    int data_time = 0;
    int n_switch = 0;
    //
    // guarantee that a full chop cycle is performed in chopped observations
    if(chopmode == "tp") {
        int divisor = 1;
    } else {
        divisor = 2;
    }
    // Try 16 bit mode
    int dpmax = 5;
    {int,double[]} dataparms = DataTaking(backendreadoutparms,dpmax);
    int dpmin = dataparms{0};
    int nstep = dpmax - dpmin;
    // Check read out times
    for(int istep = 0 .. nstep) {
        int idiv = dpmax - istep;
        if(observing_time % (divisor * idiv) == 0) {
            data_time = idiv;
            n_switch = observing_time / idiv;
        }
    }
    if(data_time == 0) {
        debug_print("The integration time of " + observing_time + "s cannot be split " + "into short integrations - trying 24 bit mode.");
        // Try 24 bit mode
        dpmax = 10;
        dataparms = DataTaking(backendreadoutparms,dpmax);
        dpmin = dataparms{0};
        nstep = dpmax - dpmin;
        // Check read out times
        for(int istep1 = 0 .. nstep) {
            idiv = dpmax - istep1;
            if(observing_time % (divisor * idiv) == 0) {
                data_time = idiv;
                n_switch = observing_time / idiv;
            }
        }
    }
    if(data_time == 0) {
        error("The integration time of " + observing_time + "s cannot be split " + "into equal integrations  <= 10s.");
    }
    //

    return [data_time,n_switch];
}

// Get load temperatures
{double,double} procedure LoadTemperatures {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    // Get temperatures
    double[] temp = CalibrationReader("loadtemp",["hot_temperature","cold_temperature"],band,lo_freq);
    double t_hot = temp[0];
    double t_cold = temp[1];
    // Get coupling specific for each band
    temp = CalibrationReader("loadcoupling",["hot_coupling","cold_coupling"],band,lo_freq);
    double c_hot = temp[0];
    double c_cold = temp[1];
    // Translate into radiation temperatures
    double hoverk = 4.7992E-5;
    double j_hot = hoverk * lo_freq / (exp(hoverk * lo_freq / t_hot) - 1.0);
    double j_cold = hoverk * lo_freq / (exp(hoverk * lo_freq / t_cold) - 1.0);
    // Coupling 
    double j_hot_eff = j_hot * c_hot + j_cold * (1.0 - c_hot);
    double j_cold_eff = j_cold * c_cold + j_hot * (1.0 - c_cold);

    return {j_hot_eff,j_cold_eff};
}

//Set LCU6Lb back to standby status, procedure
procedure LCU6Lb_standby_proc_fm {
    string band = "6b"; // HIFI band
    double lo_freq = 1600.0 in [1575.0,1700.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

// =======================================================
block Virtual_Machine_Test_block_fm HIFI 3650 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //Configure HRS
    HRS_config_att_lo_fm(band,hrs_mode);
    HRS_config_resol_fm(band,hrs_mode);
    // Take total power spectrum
    //==========================
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    // delay to ensure total power finished
    //
}

// Take fast chop spectra, block
block Spectro_fast_chop_block_fm HIFI 3608 {
    string band = "1a"; // HIFI band
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
    double[] chop_angle = [-1.0,+1.0]; //The two angles to chop between
    int[] timing_parms = [1,2,1]; //n_wbs_start, n_wbs1 and n_hrs_trans
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //
    int n_wbs_start = timing_parms[0];
    int n_wbs1 = timing_parms[1];
    int n_hrs_trans = timing_parms[2];
    //
    //Compute data-rate
    int total_time = iceil(chop_phase * double(n_wbs_start * n_wbs1));
    double[] rates = ILT_datarate_proc_fm(band,backend,"fastchop",total_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    HIFI_Spectr_fast_chop_proc_fm(chop_angle[0],chop_angle[1],n_wbs1,n_hrs_trans);
    //This probably needs to be adapted
    Apply_Fast_Chop_delay(total_time,n_wbs_start,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the OTF observing mode
procedure OTFLoadChopNoRef_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int n_perline = 10; // Number of frequency switch cycles per line
    int n_linesperscan = 1; // Number of lines between two load holds
    int nlines_tot = 10; // Total number of lines to go
    bool end_load_on = false; // Need for load after each pointing phase
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,2,2,40,10,20,0]; // Timing of the observation from telescope
    int loadlength = 50; // Load duration
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            HIFISetHK("normal",false);
            // First load measurement
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 8) {
            // OTF integration
            // Check whether this is the first line
            if((state[2] + n_linesperscan - 1) % n_linesperscan == 0) {
                HIFIConfigureLoadChopIntegration(data_time,n_perline,band,lo_freq,backendreadoutparms);
            }
            HIFILoadChopOnIntegration(data_time,n_perline,band,lo_freq,rates);
            runintostate = false;
        }
        if(state[0] == 6) {
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            if(state[2] * state[3] == nlines_tot) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        if(state[0] == 5) {
            // apply only if I do not come from a load-hold
            if(!runintostate) {
                delay(readoutdead);
                if(end_load_on) {
                    // Perform final load measurement 
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                }
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

// Initialisation of FPU, block with both MSA in use
// It is for cold context !
block Init_MSA_aot HIFI 6200 {
    string band = "4a"; // HIFI band
    string chop_loop = "CLOSE";
    double lo_freq = 978.2; //LO frequency
    bool power_fcu = true; //whether needs full FPU configuration (true) or just freq-dependent adjustement (false)
    string hbb_heater = "ON" in ["ON","OFF"]; //hot source on/off
}{
    //Store rest frequency
    double rest_lofreq = lo_freq;
    //LO frequency uncorrected from VelCorr
    // Perform radial velocity correction
    lo_freq = VelCorrFreq(rest_lofreq);
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //  
    double calibcurrent = result_d[7]{0};
    if(hbb_heater == "ON") {
        result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,lo_freq);
        calibcurrent = result_d[0]{0};
    }
    //
    //
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,lo_freq);
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range: not necessary anymore with MIB134
    //chopper = Check_Chopper_Range(chopper);  
    //
    //Check whether we need to go through a complete FPU configuration from scratch
    //Standard Init of FPU
    if(power_fcu) {
        //Switch on upconverter, assuming chopper and mixers are also ON
        Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
        //
        HIFI_Configure_FCU_proc_aot(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
        //
        result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,rest_lofreq);
        int config_fpu_delay = iround(result_d[0]{0});
        delay(config_fpu_delay);
        //
        //Magnet are so far at maximum value. Now set to nominal
        if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
            result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
            Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
            Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
            delay(1);
        }
        //In case of band 6 or 7, bias have been set to 6mV. Now set to nominal
        if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
            result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
            Mixerbias(result_d[0]{0},result_d[1]{0});
        }
        //Reduced FPU configuration 
    } else {
        //In case of HEB, we have so far the max bias as values
        if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
            result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
            bias_H = result_d[0]{0};
            bias_V = result_d[1]{0};
        }
        Hifi_HIFI_noop();
        Hifi_HIFI_Config_mxbias_dpact($BBID,bias_H,bias_V,diplex_H,diplex_V);
        delay(1);
    }
    //
    // Removed to reduce No of TC
    // Hifi_HIFI_non_periodic_hk_FCU ();
}

//HIFI LO tuning, block
//Target current is read from look-up table
block LO_tuning_HEB_block_fm HIFI 3677 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string mixer_polarization = "H" in ["H","V","B"]; //The polarization to be used for the tuning
    double target_current = 1.0; //Target mixer current
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    //string mixer_polarization = result[0]{1};
    //
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    //double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        //target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        //target_current = 0.5*(result[1]{0}+result[0]{0}); 
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double middle_d2 = result[0]{0};
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    //
    //delay(5);	//to settle at this value
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

// Standby of FPU with internal source off, block
block Band0_fm HIFI 3299 {
    string band = "0";
    string chop_loop = "CLOSE"; // Chopper Loop status
}{
    Start_block();
    //
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h","diplex_h_ctrl_mode"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    //
    int diplex_h_ctrl_mode = iround(result_d[10]{0});
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v","diplex_v_ctrl_mode"],band,0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    int diplex_v_ctrl_mode = iround(result_d[10]{0});
    //
    string chop_sine_s = "ON";
    //
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //To get standby with source on, use Band0_hbb_on
    result_d = ConfigurationReader("name_confilfpu",["bias_standby_h","diplexer_standby_h","bias_standby_v","diplexer_standby_v","chop_M3right"],band,0.0);
    //
    double bias_H = result_d[0]{0};
    double diplex_H = result_d[1]{0};
    double bias_V = result_d[2]{0};
    double diplex_V = result_d[3]{0};
    //  double chopper = result_d[4]{0};
    //
    //Retrieve magnets Magnet are so far at maximum value. Now set to nominal
    double magnetcurrent_H = result_d[1]{0};
    double magnetcurrent_V = result_d[4]{0};
    //
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_standby_h","magnet_standby_v"],band,0.0);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,0.0);
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReaderWarm("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
}

////////////////////////////////////
// OTF frequency switch observing mode without baseline calibration
// 
{string,double,double}[] procedure HifiMappingProcFSwitchOTFNoRefSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints = 10 in [1,720]; // Number of data dumps per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period defines number of lines between two loads
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // inherit from load-chop mode
    {string,double,double}[] retvalues = HifiMappingProcLoadChopOTFNoRefSequencerInit(naifid,ra,dec,lineDistance,nlines,stepsize,npoints,band,lo_freq,effResolution,oneGHzReference,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_cycles,load_interval,docommands);

    return retvalues;
}

// Get approximate initialization times
int procedure GetRoughInitLength {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    bool fsw = false; // tuning for frequency switch?
}{
    if(fsw) {
        double[] idur = CalibrationReader("tunetime",["TuneHifiFsw"],band,lo_freq);
    } else {
        idur = CalibrationReader("tunetime",["TuneHifi"],band,lo_freq);
    }
    int initlength = iceil(idur[0]) + 2;

    return initlength;
}

//  LCU5a configuration into SAFE mode, procedure
procedure LCU5a_config_safe_proc_fm {
    string band = "5a"; // HIFI band
    double lo_freq = 1150.0 in [1127.0,1178.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

////////////////////////////////////
// Radial veocity correction
double procedure VelCorrFreq {
    double lo_freq = 978200.0; // LO frequency in MHz
}{
    double clight = 299999.6;
    // light velocity in km/s
    // classic correction - non-relativistic
    // to keep time estimates constant all shifts above a reasonable
    // limit are ignored - all lines will still fall into the spectrometers
    double velmax = 30.7;
    double appliedvel = max(min($RADVEL,velmax),-velmax);
    // $RADVEL in classic definition with positive for redshifted
    double lo_corr = lo_freq - appliedvel * lo_freq / clight;

    return lo_corr;
}

//  LCU2b configuration into SAFE mode, procedure
procedure LCU2b_config_safe_proc_fm {
    string band = "2b"; // HIFI band
    double lo_freq = 750.0 in [724.0,793.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

/////////////////////////////////////////////////////////
// WBS configuration with maximum attenuation, procedure
// Laser can be chosen
procedure WBS_config_proc_max_att_w_laser_fm {
    string band = "1a"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
}{
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = 7;
    int hwh_att_band3 = 7;
    int hwh_att_band2 = 7;
    int hwh_att_band1 = 7;
    int hwh_att_in = 15;
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //delay(wbs_config_delay);
    //V-Polarization
    //Get configuration parameters
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = 7;
    int hwv_att_band3 = 7;
    int hwv_att_band2 = 7;
    int hwv_att_band1 = 7;
    int hwv_att_in = 15;
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    //Wait delay to allow all setting to be configured
    delay(wbs_config_delay);
}

// New implementation of the WBS zero and comb measurement 
//
// Returns dangling transmission time
//
int block WBS_Zero_FCal HIFI 6014 {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double lo_freq = 978200.0; // LO frequency
}{
    // Get delays 
    {double,string}[] result = ConfigurationReader("name_delays",["wbs_new_comb_delay"],band,lo_freq);
    int wbs_comb_delay = iround(result[0]{0});
    int delay1 = 2;
    int delay2 = 3;
    int delay3 = wbs_comb_delay - delay1 - delay2;
    // Get attenuators for comb measurement
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_att_band4_comb","hwh_att_band3_comb","hwh_att_band2_comb","hwh_att_band1_comb","hwh_att_in_comb"],band,0.0);
    int hwh_att_band4 = iround(result_d[0]{0});
    int hwh_att_band3 = iround(result_d[1]{0});
    int hwh_att_band2 = iround(result_d[2]{0});
    int hwh_att_band1 = iround(result_d[3]{0});
    int hwh_att_in = iround(result_d[4]{0});
    // Data rate computation
    // The HIFI command is restricted to always read out both full WBS
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} fullreadoutparms = FrequencyCalibrationParms(true,true,false,false);
    // First part - zero
    // data rate
    {int,double[]} fdataparms = DataTaking(fullreadoutparms,delay1);
    // set data rates
    non_ess_hk_data_rate(fdataparms{1}[2] / 1024.0);
    data_rate(fdataparms{1}[0] / 1024.0);
    // Call command
    Hifi_HIFI_WBS_Calibrate($BBID,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    delay(delay1);
    // data rates for other steps
    fullreadoutparms = FrequencyCalibrationParms(false,true,true,true);
    // set data rates
    fdataparms = DataTaking(fullreadoutparms,delay2);
    non_ess_hk_data_rate(fdataparms{1}[2] / 1024.0);
    data_rate(fdataparms{1}[0] / 1024.0);
    delay(delay2);
    fullreadoutparms = FrequencyCalibrationParms(true,true,true,true);
    // set data rates
    fdataparms = DataTaking(fullreadoutparms,delay3);
    non_ess_hk_data_rate(fdataparms{1}[2] / 1024.0);
    data_rate(fdataparms{1}[0] / 1024.0);
    delay(delay3);
    // read-out time
    int readout = fdataparms{0};
    // reset data rates
    non_ess_hk_data_rate(fdataparms{1}[1] / 1024.0);
    data_rate(0.0);
    //
    // additional delay for packet transmission before next zero depends
    // on zero duration - needs to be introduced on higher level

    return readout;
}

// Procedure to perform the WBS tuning including the counting
// of the science data, must be called within a building block
procedure Tune_WBS_aot {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int tune_target = 80; // Tuning target level
}{
    //Get delay
    {double,string}[] result_d = ConfigurationReader("name_delays",["wbs_tune_delay"],band,0.0);
    int wbs_tune_delay = iround(result_d[0]{0});
    // data frame transmission time (always 3 spectra)
    int data_time = wbs_tune_delay / 3;
    int rest_delay = wbs_tune_delay - 3 * data_time;
    wbs_tune_delay = wbs_tune_delay - rest_delay;
    // Compute data rates
    // The HIFI command reads out both full WBS
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} fullreadoutparms = FrequencyCalibrationParms(true,true,false,false);
    {int,double[]} fdataparms = AllDataRates(fullreadoutparms,data_time,false);
    // set data rates (IF power packets are ignored here)
    data_rate(fdataparms{1}[0] / 1024.0);
    // Call tuning command
    Hifi_HIFI_Tune_WBS($BBID,tune_target);
    delay(wbs_tune_delay);
    // reset data rates
    data_rate(0.0);
    delay(rest_delay);
}

//  LCU5a configuration and tuning, procedure
procedure LCU5a_config_tune_proc_fm {
    string band = "5a"; // HIFI band
    double lo_freq = 1150.0 in [1127.0,1178.0]; //LO frequency
    double drain_2_factor = 100.0; //Percentage factor of the targetted drain voltage
}{
    error("This module is obsolete: use LO_tuning_block_fm  instead");
}

//TM to control FDIR on LOU temp
block Disable_LO_FDIR_temperatures_block_mois HIFI 3852 {
}{
    // BBID needs to be set manually as the main TC command has no BBID argument
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    delay(1);
    //
    Hifi_HIFI_LOU_T_check_off();
    delay(1);
    //
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure SScanDoubleChop_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int nfreq = 4; // Number of frequency points per IF
    bool dsb = true; // Both sidebands covered
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int grouplen = 1; // Number of frequency steps per nodding phase
    int n_cycles = 1; // Number of ON-OFF cycles
    int freqsteps = 4; // Total number of frequencies
    double avnumchop_on = 1.0; // Average number of ON chop cycles per frequency
    double avnumchop_off = 1.0; // Average number of OFF chop cycles per frequency
    bool fs = false; // whether frequency switch used
    double tscan = 60.0; // Total average duration of one cycle
    {double,double,double,double,double} tact = {10.0,4.9,4.9,0.05,0.05}; // Field of actual dead and integration times
}{
    double inttimeperonphase = tact{1};
    // Actual integration time in ON phase
    double inttimeperoffphase = tact{2};
    // Actual integration time in OFF phase
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    // Use DSB noise for long spctral scans
    if(dsb) {
        double idealnoiselsb = idealvalues{1} * idealvalues{1};
        double idealnoiseusb = idealvalues{3} * idealvalues{3};
        double idealnoise = idealnoiselsb * idealnoiseusb / (idealnoiselsb + idealnoiseusb);
    } else {
        idealnoise = idealvalues{1} * idealvalues{1};
    }
    double obsnoise = noisevalues{0} * noisevalues{0};
    // rescale for range coverage
    double accumulation = double(freqsteps) / double(nfreq);
    idealnoise = idealnoise * accumulation;
    double efficiency = idealnoise / obsnoise;
    // Compute the actual integration time
    double maxsteps = double(freqsteps * n_cycles);
    double posinttime = 2.0 * maxsteps * avnumchop_on * inttimeperonphase;
    double posofftime = 2.0 * maxsteps / double(grouplen) * avnumchop_off * inttimeperoffphase;
    int instrumenttime = iceil(maxsteps * tscan);
    // Check total integration time
    double timeefficiency = (posinttime + posofftime) / double(totaltime);
    // Noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posofftime,timeefficiency,efficiency,relnoise,fs);
}

//TM check when switched off
procedure Mode_status_check_switched_off {
}{
    mois_comment("Checking instrument status in switched off mode");
    mois_tmcheck("Check that the HK parameter HI_FCU_S, HI_WBSH_S, HI_WBSV_S, HI_HRSH_S, HI_HRSV_S and HI_LCU_S are all OFF.");
}

/////////////////////////////////////////////////////////////////////////////
// Auxiliary procedures
/////////////////////////////////////////////////////////////////////////////
// Function returning generic HRS mode
string[] procedure GetHrsMode_proc_fm {
    string[] input_hrs_mode = ["wb","wb"]; // HRS resolution mode
}{
    string[] output_hrs_mode = ["wb","wb"];
    //Test all possible resolution modes
    //H-polar
    if(input_hrs_mode[0] == "hr" || input_hrs_mode[0] == "hr_high" || input_hrs_mode[0] == "hr_low") {
        output_hrs_mode[0] = "hr";
    }
    if(input_hrs_mode[0] == "mr") {
        output_hrs_mode[0] = "mr";
    }
    if(input_hrs_mode[0] == "lr") {
        output_hrs_mode[0] = "lr";
    }
    //V-polar
    if(input_hrs_mode[1] == "hr" || input_hrs_mode[1] == "hr_high" || input_hrs_mode[1] == "hr_low") {
        output_hrs_mode[1] = "hr";
    }
    if(input_hrs_mode[1] == "mr") {
        output_hrs_mode[1] = "mr";
    }
    if(input_hrs_mode[1] == "lr") {
        output_hrs_mode[1] = "lr";
    }
    //

    return output_hrs_mode;
}

//General script to clear error flags and set to nominal, block
block LCU_CLEAR_ERROR_block_fm HIFI 3666 {
}{
    //
    //Start_block();
    //Clear error flags
    Hifi_HIFI_LCU_Single($BBID,"HL_CLR_ERR");
    //Switch back to nominal
    Hifi_HIFI_HL_Normal($BBID);
    {double,string}[] result = ConfigurationReader("name_delays",["set_to_nominal_delay"],"0",0.0);
    int set_to_nominal_delay = iround(result[0]{0});
    delay(set_to_nominal_delay);
    //
}

////////////////////////////////////
// Fast chop DBS cross observing mode - special version for Jupiter
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcJupiterFastDBSCross {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the two raster lines
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Engineering - Jupiter - DBS Cross Map fastChop",{data_time,0,n_int_on,n_switch_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    // Two changes relative to the normal DBS raster
    // 1) The longer load duration is enforced by zero resolution
    {double,double} loadResolution = {0.0,effResolution{1}};
    // 2) I assume that the tuning duration does not depend on the tuning level
    // so that the normal pre_timing can be reused.
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = FastDBSRaster_pre_timing(2,npoints,band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,double[],double[],int[],double,double,int,int,int,int,int,int} tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = custom_map_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSCross_post_timing(pre_timing,telescopetimes,npoints,n_switch_on,n_cycles,load_interval,true);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",post_timing{1},n_cycles);
    telescopetimes = custom_map_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int scansize = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        JupiterFastDBSRaster_commanding(band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,true);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastDBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,2,npoints,n_cycles,n_seq * n_int_on * imax(n_load,1),tact);
    // Correct for double counting of central point
    // The central point is returned only
    double multiplier = sqrt(0.5);
    noisevalues{0} = noisevalues{0} * multiplier;
    noisevalues{1} = noisevalues{1} * multiplier;
    noisevalues{2} = noisevalues{2} * multiplier;
    noisevalues{3} = noisevalues{3} * multiplier;
    noisevalues{4} = noisevalues{4} / multiplier;
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// FPU Standby with HBB On, block
block Band0warm_hbb_on_fm HIFI 3295 {
    string band = "0"; // HIFI band
    string chop_loop = "CLOSE"; // Chopper Loop status
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReaderWarm("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReaderWarm("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current_on"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    result_d = ConfigurationReaderWarm("name_confilfpu",["bias_standby_h","diplexer_standby_h","bias_standby_v","diplexer_standby_v","diplex_h_ctrl_mode","diplex_v_ctrl_mode","chop_M3right"],band,0.0);
    //
    double bias_H = result_d[0]{0};
    double diplex_H = result_d[1]{0};
    double bias_V = result_d[2]{0};
    double diplex_V = result_d[3]{0};
    int diplex_h_ctrl_mode = iround(result_d[4]{0});
    int diplex_v_ctrl_mode = iround(result_d[5]{0});
    //
    //Retrieve magnets Magnet are so far at maximum value. Now set to nominal
    double magnetcurrent_H = result_d[1]{0};
    double magnetcurrent_V = result_d[4]{0};
    //
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReaderWarm("name_confilfpu",["magnet_standby_h","magnet_standby_v"],band,0.0);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
}

//HIFI-COP-1.2-UPC_FT
//NOT USED ANY LONGER - IF_FT REPLACED IT
obs HifiEng_UPC_FT_COP {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(UPC_FT_COP_proc_ops(prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            UPC_FT_COP_proc_ops(prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

//////////////////////////////////////////////////////////////////
// Procedure to compute detailed pre timing for the version of the
// load chop mode with baseline measurement
// 
{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} procedure LoadChop_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_chop_on = 2 in [1,900]; // number of half load-sky-sky-load cycles on ON
    int n_chop_off = 2 in [1,900]; // number of half load-sky-sky-load cycles on OFF
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF calibration cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    CheckDataTaking(backendreadoutparms,data_time_off);
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    // Compute parameters for the instrument timing
    int on_inttime = 2 * n_chop_on * data_time;
    int off_inttime = 2 * n_chop_off * data_time_off;
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // For double phases I can use the added jitterdead in both phases for load
    int halfloadlength = (loadlength - jitterdead + 1) / 2;
    // Compare load interval and position switch interval
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    int n_load_on = on_inttime / load_spacing;
    int n_load_off = off_inttime / load_spacing;
    // This determines the order of the loops
    if(load_spacing > 2 * on_inttime) {
        int n_per_on = n_chop_on;
        bool end_load_on = false;
        int on_pointing = on_inttime + jitterdead;
    } else {
        n_per_on = n_chop_on / (n_load_on + 1);
        if(n_per_on < 1) {
            SError("Chop phase length on source too long relative to load period.");
        }
        end_load_on = true;
        on_inttime = 2 * n_per_on * (n_load_on + 1) * data_time;
        on_pointing = on_inttime + halfloadlength + n_load_on * loadlength + jitterdead;
    }
    if(load_spacing > 2 * off_inttime) {
        int n_per_off = n_chop_off;
        bool end_load_off = false;
        int off_pointing = off_inttime + jitterdead;
    } else {
        n_per_off = n_chop_off / (n_load_off + 1);
        if(n_per_off < 1) {
            SError("Chop phase length on OFF position too long relative to load period.");
        }
        end_load_off = true;
        off_inttime = 2 * n_per_off * (n_load_off + 1) * data_time_off;
        off_pointing = off_inttime + halfloadlength + n_load_off * loadlength + jitterdead;
    }
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,false);
    }
    initlength = initlength + loadlength;
    // Compute the overall cycle length
    // First estimate of the load interval
    int n_loadinterval = imax(load_interval / (on_pointing + off_pointing),1);
    // Exception handling for very uneven phases
    if(end_load_on || end_load_off) {
        n_loadinterval = 1;
    }
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed for telescope call and post_timing processing

    return {on_inttime,off_inttime,on_pointing,off_pointing,loadlength,jitterdead,load_spacing,n_loadinterval,n_per_on,n_per_off,n_load_on,n_load_off,end_load_on,end_load_off,initlength,dangling};
}

////////////////////////////////////////
// Standing wave analysis, procedure
// This is like a radiometry: 4 spectra
// retune version
procedure Standing_wave_retune_fm_COP {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    double[] lo_freq_input = [500.0,500.15,0.02]; //Start, end and step lo_freq for the LO scan
    string los_code = "sc" in ["sc","sh","ss"]; //The line-of-sight code: sc (sky-CBB), sh (sky-HBB), ss (sky-sky)
    int nb_retune = 5; //frequency at which we retune
}{
    // Initial LO tuning at centre frequency of scan  (NDW)
    // Not applicable here
    double lo_freq_ref = (lo_freq_input[0] + lo_freq_input[1]) / 2.0;
    //LO_tuning_block_fm(band, lo_freq_ref); 
    double lo_freq = lo_freq_input[0];
    //
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_stndwave_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Loop on LO frequencies. It is assumed that the LO is tuned at the middle frequency of the scan
    //
    int retune = 0;
    while(lo_freq <= lo_freq_input[1]) {
        //
        //We will retune at the running frequency every settings (starting with the first)
        retune = iround((lo_freq - lo_freq_input[0]) / lo_freq_input[2]) % nb_retune;
        if(retune == 0) {
            LO_tuning_block_fm(band,lo_freq);
        } else {
            //Set synthesizer to new LO freq.
            LCU_config_nominal_noretune_block_fm(band,lo_freq,lo_freq_ref);
        }
        //
        if(los_code == "sc") {
            //Pair towards sky-CBB
            Sky_Cold_fm_COP(band,integ_time,hrs_mode,backend);
        }
        if(los_code == "sh") {
            //Pair towards sky-HBB
            Sky_Hot_fm_COP(band,integ_time,hrs_mode,backend);
        }
        if(los_code == "ss") {
            //Pair towards sky-sky
            Sky_Sky_fm_COP(band,integ_time,hrs_mode,backend);
        }
        //Increase lo_freq
        lo_freq = lo_freq + lo_freq_input[2];
    }
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the OTF observing mode
procedure OTFFSwitchNoRef_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int n_perline = 10; // Number of frequency switch cycles per line
    int n_linesperscan = 1; // Number of lines between two load holds
    int nlines_tot = 10; // Total number of lines to go
    bool end_load_on = false; // Need for load after each pointing phase
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,2,2,40,10,20,0]; // Timing of the observation from telescope
    int loadlength = 50; // Load duration
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFIFsw(band,lo_freq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            HIFISetHK("normal",false);
            // First load measurement
            DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 8) {
            // OTF integration
            // Check whether this is the first line
            if((state[2] + n_linesperscan - 1) % n_linesperscan == 0) {
                HIFIConfigureFSwitchIntegration(data_time,n_perline,band,lo_freq,backendreadoutparms);
            }
            HIFIFSwitchOnIntegration(data_time,n_perline,band,lo_freq,rates);
            runintostate = false;
        }
        if(state[0] == 6) {
            delay(readoutdead);
            DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
            if(state[2] * state[3] == nlines_tot) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        if(state[0] == 5) {
            // apply only if I do not come from a load-hold
            if(!runintostate) {
                delay(readoutdead);
                if(end_load_on) {
                    // Perform final load measurement 
                    DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
                }
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

// BLOCK : Functional Test No 2 (HRS Correlation modes Test)
block HRS_functional_test_No_2_Corr_block_fm HIFI 3623 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    int repeats = 5;
    //Fill in block parameter names for each mode - consequence of SPR-0198
    string[] hrs_blocks_corr_ultra = ["corr_ultra","corr_ultra","corr_ultra","corr_ultra","corr_ultra","corr_ultra","corr_ultra","corr_ultra"];
    string[] hrs_blocks_corr_wide = ["corr_wide","corr_wide","corr_wide","corr_wide","corr_wide","corr_wide","corr_wide","corr_wide"];
    string[] hrs_blocks_corr_low = ["corr_hilonom","low","corr_low","low_nominal","corr_low_nom","low","corr_low","high_nominal_low"];
    string[] hrs_blocks_corr_nom = ["corr_hilonom","high_nominal","high_nominal","low_nominal","corr_low_nom","high_nominal","high_nominal","high_nominal_low"];
    string[] hrs_blocks_corr_high = ["corr_hilonom","high_nominal","high_nominal","high","high","high_nominal","high_nominal","high_nominal_low"];
    // Configure spectroscopy
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    // Loops on the different configurations of the HRS
    //======================================
    //Calls the 5 modes to be checked
    //Corr_ultra
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_corr_ultra[0],hrs_blocks_corr_ultra[1],hrs_blocks_corr_ultra[2],hrs_blocks_corr_ultra[3],hrs_blocks_corr_ultra[4],hrs_blocks_corr_ultra[5],hrs_blocks_corr_ultra[6],hrs_blocks_corr_ultra[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_corr_ultra[0],hrs_blocks_corr_ultra[1],hrs_blocks_corr_ultra[2],hrs_blocks_corr_ultra[3],hrs_blocks_corr_ultra[4],hrs_blocks_corr_ultra[5],hrs_blocks_corr_ultra[6],hrs_blocks_corr_ultra[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Corr_wide
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_corr_wide[0],hrs_blocks_corr_wide[1],hrs_blocks_corr_wide[2],hrs_blocks_corr_wide[3],hrs_blocks_corr_wide[4],hrs_blocks_corr_wide[5],hrs_blocks_corr_wide[6],hrs_blocks_corr_wide[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_corr_wide[0],hrs_blocks_corr_wide[1],hrs_blocks_corr_wide[2],hrs_blocks_corr_wide[3],hrs_blocks_corr_wide[4],hrs_blocks_corr_wide[5],hrs_blocks_corr_wide[6],hrs_blocks_corr_wide[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Corr_low
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_corr_low[0],hrs_blocks_corr_low[1],hrs_blocks_corr_low[2],hrs_blocks_corr_low[3],hrs_blocks_corr_low[4],hrs_blocks_corr_low[5],hrs_blocks_corr_low[6],hrs_blocks_corr_low[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_corr_low[0],hrs_blocks_corr_low[1],hrs_blocks_corr_low[2],hrs_blocks_corr_low[3],hrs_blocks_corr_low[4],hrs_blocks_corr_low[5],hrs_blocks_corr_low[6],hrs_blocks_corr_low[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Corr_nominal
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_corr_nom[0],hrs_blocks_corr_nom[1],hrs_blocks_corr_nom[2],hrs_blocks_corr_nom[3],hrs_blocks_corr_nom[4],hrs_blocks_corr_nom[5],hrs_blocks_corr_nom[6],hrs_blocks_corr_nom[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_corr_nom[0],hrs_blocks_corr_nom[1],hrs_blocks_corr_nom[2],hrs_blocks_corr_nom[3],hrs_blocks_corr_nom[4],hrs_blocks_corr_nom[5],hrs_blocks_corr_nom[6],hrs_blocks_corr_nom[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Corr_high
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_corr_high[0],hrs_blocks_corr_high[1],hrs_blocks_corr_high[2],hrs_blocks_corr_high[3],hrs_blocks_corr_high[4],hrs_blocks_corr_high[5],hrs_blocks_corr_high[6],hrs_blocks_corr_high[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_corr_high[0],hrs_blocks_corr_high[1],hrs_blocks_corr_high[2],hrs_blocks_corr_high[3],hrs_blocks_corr_high[4],hrs_blocks_corr_high[5],hrs_blocks_corr_high[6],hrs_blocks_corr_high[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //}
}

// Diplexer calibration for a given mixer band with hotcold measurements
// Measures hot and cold series at diplexer settings between two minima of 
// mixer coupling
procedure Diplexer_calibration_hotcold_proc_fm {
    string band = "3a" in ["3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI LO band
    double lo_freq = 807.0; //LO frequency  
}{
    //
    Check_Band_vs_Freq_proc_fm(band,lo_freq);
    //
    double if_freq = 6.0;
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        if_freq = 3.6;
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        double bias_max_h = result[0]{0};
        double bias_max_v = result[1]{0};
        result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        double bias_normal_h = result[0]{0};
        double bias_normal_v = result[1]{0};
    }
    //Fetch diplexer settings for the scan: we may jump over a period of the tooth
    //So we need to assess the slope to have a symetrical scan.
    //Previous minima
    double[] result_dip = Get_Diplexer_setting(band,lo_freq - if_freq / 2.0);
    double diplex_H_prev = result_dip[0];
    double diplex_V_prev = result_dip[1];
    //Optimum value
    result_dip = Get_Diplexer_setting(band,lo_freq);
    double diplex_H_opt = result_dip[0];
    double diplex_V_opt = result_dip[1];
    //Next minima
    result_dip = Get_Diplexer_setting(band,lo_freq + if_freq / 2.0);
    double diplex_H_next = result_dip[0];
    double diplex_V_next = result_dip[1];
    //Get effective span
    double diplex_H_max = max(diplex_H_prev,diplex_H_next);
    double diplex_V_max = max(diplex_V_prev,diplex_V_next);
    double diplex_H_min = min(diplex_H_prev,diplex_H_next);
    double diplex_V_min = min(diplex_V_prev,diplex_V_next);
    //
    double diplex_H_span = 2.0 * (diplex_H_opt - diplex_H_min);
    double diplex_H_start = diplex_H_min;
    double diplex_H_end = min(diplex_H_min + diplex_H_span,2.24);
    double diplex_V_span = 2.0 * (diplex_V_opt - diplex_V_min);
    double diplex_V_start = diplex_V_min;
    double diplex_V_end = min(diplex_V_min + diplex_V_span,2.24);
    //
    if(diplex_H_opt < diplex_H_next) {
        diplex_H_span = 2.0 * (diplex_H_prev - diplex_H_opt);
        diplex_H_end = diplex_H_prev;
        diplex_H_start = max(diplex_H_end - diplex_H_span,-2.24);
    }
    if(diplex_V_opt < diplex_V_next) {
        diplex_V_span = 2.0 * (diplex_V_prev - diplex_V_opt);
        diplex_V_end = diplex_V_prev;
        diplex_V_start = max(diplex_V_end - diplex_V_span,-2.24);
    }
    if(diplex_H_opt > diplex_H_prev) {
        diplex_H_span = 2.0 * (diplex_H_opt - diplex_H_next);
        diplex_H_start = diplex_H_next;
        diplex_H_end = min(diplex_H_start + diplex_H_span,2.24);
    }
    if(diplex_V_opt > diplex_V_prev) {
        diplex_V_span = 2.0 * (diplex_V_opt - diplex_V_next);
        diplex_V_start = diplex_V_next;
        diplex_V_end = min(diplex_V_start + diplex_V_span,2.24);
    }
    //
    //Re-compute adjusted spans: they know ensure scans within the [-2.24,+2.24] mA range
    diplex_H_span = diplex_H_end - diplex_H_start;
    diplex_V_span = diplex_V_end - diplex_V_start;
    //Hard-coded values:
    int n_steps = 20;
    double stepTime = 0.1;
    //Step time in seconds: GRANULARITY IS 0.1sec!!!!
    double diplexer_current_step = -1.0 * min(diplex_H_span,diplex_V_span) / double(n_steps - 1);
    //
    //Set FPU at operational frequency
    Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //Perform LO tuning at optimum diplexer settings and a target of 0.035mV
    LO_tuning_w_targetC_block_fm(0.035,band,lo_freq,"H");
    //Set diplexers to the starting value to tune HRS
    Set_Diplexer_current_block_fm(diplex_H_end,diplex_V_end);
    //
    //Configure HRS: use hard-coded configuration: wb1 for SIS, wb8 for HEB
    string[] hrs_mode = ["wb1","wb1"];
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //
    //Configure spectroscopy for slowchop hotcold
    int integ_time = 2;
    string backend = "hrs";
    int[] res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    int total_time = res[0] * res[1];
    //
    HRS_config_block_fm(band,hrs_mode);
    HRS_tune_block_fm(band);
    //
    //In case of band 6 or 7, use special procedure
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        //Exit from oscillation regime
        Mixerbias_block_fm(bias_max_h,bias_max_v);
        Mixerbias_block_fm(bias_normal_h,bias_normal_v);
        //Get back to optimum diplexers
        result_dip = Get_Diplexer_setting(band,lo_freq);
        Set_Diplexer_current_block_fm(result_dip[0],result_dip[1]);
        //Take hotcold spectrum 
        Hot_cold(band,hrs_mode,backend,total_time,"slowchop",20,1);
        //Do first half scan: start value needs to be above the middle
        double diplex_H_first = result_dip[0] + abs(diplexer_current_step) / 2.0;
        double diplex_V_first = result_dip[1] + abs(diplexer_current_step) / 2.0;
        Scan_diplexer_IF_block_fm(band,diplex_H_first,diplex_V_first,diplexer_current_step,11,stepTime,lo_freq);
        //Get back to optimum diplexers
        result_dip = Get_Diplexer_setting(band,lo_freq);
        Set_Diplexer_current_block_fm(result_dip[0],result_dip[1]);
        //Take hotcold spectrum 
        Hot_cold(band,hrs_mode,backend,total_time,"slowchop",20,1);
        //Do second half scan: start value needs to be below the middle
        double diplex_H_second = result_dip[0] - abs(diplexer_current_step) / 2.0;
        double diplex_V_second = result_dip[1] - abs(diplexer_current_step) / 2.0;
        Scan_diplexer_IF_block_fm(band,diplex_H_second,diplex_V_second,-1.0 * diplexer_current_step,11,stepTime,lo_freq);
    } else {
        //Perform scan
        Scan_diplexer_IF_block_fm(band,diplex_H_end,diplex_V_end,diplexer_current_step,n_steps,stepTime,lo_freq);
        //
    }
    //Get back to optimal settings
    result_dip = Get_Diplexer_setting(band,lo_freq);
    Set_Diplexer_current_block_fm(result_dip[0],result_dip[1]);
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        //Take hotcold spectrum ?
        Hot_cold(band,hrs_mode,backend,total_time,"slowchop",20,1);
    }
    //
}

// Procedure to compute all parameters needed in a Configure_spectroscopy
{int,int,int,int,int,int,int,int,int,int,int,int,int} procedure FastConfigureSpectroscopyParams {
    /* Integration time */
    int data_time = 10 in [4,128]; // data dump interval
    int n_int = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    /* Backend settings */
    bool wbs_used = true; // whether at least one WBS is used
}{
    // Get fixed parameters from configuration and calibration files
    // WBS delta time given by switch dead time
    double res = GetSkyChopDeadTime(band,lo_freq);
    int del_wbs = iceil(res * 1000.0);
    // Additional delays in the readout loops - given in OBS user manual
    {double,string}[] result = ConfigurationReader("name_delays",["add_hrs","add_wbs","add_jitter","wbs_readout","wbs_chunksize","tacc_add","max_hrs_phase","wbs_init","scos_jitter"],band,lo_freq);
    int add_hrs = iround(result[0]{0});
    int add_wbs = iround(result[1]{0});
    int add_jitter = iround(result[2]{0});
    int wbs_readout = iround(result[3]{0});
    int wbs_chunksize = iround(result[4]{0});
    int tacc_add = iround(result[5]{0});
    int max_hrs_phase = iround(result[6]{0});
    int wbs_init = iround(result[7]{0}) + iround(result[8]{0});
    // In fast chop del_hrs can be zero, but see SCR 854
    int del_hrs = add_jitter;
    // WBS
    // Fixed parameter - we never split a transfer
    int n_wbs_integr = 1;
    int n_wbs1 = 2 * n_int;
    int n_wbs_start = n_data;
    // HRS is integrated up as long as the WBS
    int n_hrs_integr = n_int;
    // Split data_time into chop phases
    // Dead time per read out (not clear whether add_wbs applies here)
    int tdead_data = 2 * (wbs_readout + add_jitter) + add_wbs - add_jitter;
    // Initial dead time - distribute over all readouts
    int tdead_init = (wbs_init + n_data - 1) / n_data;
    int chop_phase = (1000 * data_time - tdead_data - tdead_init) / (2 * n_int);
    // dead time has to be an integer multiple of the 10ms chunk time
    int tdead_chop = del_wbs + add_jitter;
    int nchunk = (tdead_chop - 1) / wbs_chunksize + 1;
    int tcorr = nchunk * wbs_chunksize - tdead_chop;
    del_wbs = del_wbs + tcorr;
    tdead_chop = tdead_chop + tcorr;
    // Accumulation time
    int t_acc_wbs = chop_phase - tdead_chop;
    // discretize in 10ms chunks
    nchunk = (t_acc_wbs - tacc_add) / wbs_chunksize;
    t_acc_wbs = nchunk * wbs_chunksize + tacc_add;
    // HRS
    // Fixed parameter here
    int r_hrs = 1;
    int t_acc_hrs = t_acc_wbs - add_jitter - del_hrs - add_hrs;
    if(t_acc_hrs > max_hrs_phase) {
        SError("Chop phase length too long for HRS. Increase chop frequency.");
    }
    // How many HRS integrations possible during WBS readout
    int t_hrs_per = t_acc_hrs + del_wbs + add_hrs;
    int n_hrs_trans = wbs_readout / t_hrs_per;
    // This currently does not work - SCR 854: skipped
    n_hrs_trans = 0;
    // Actual integration time and dead time per readout
    // If WBS is used count only the WBS time
    if(wbs_used) {
        tdead_chop = tdead_chop + tacc_add;
        int tint_act = nchunk * wbs_chunksize * n_wbs1 * n_data;
    } else {
        tdead_chop = tdead_chop + r_hrs * add_hrs;
        tdead_data = tdead_data + add_jitter - 2 * (n_hrs_trans * t_hrs_per - add_jitter);
        tint_act = t_acc_hrs * r_hrs * (n_wbs1 + 2 * n_hrs_trans) * n_data;
    }
    // Return all config_spectroscopy timing parameters

    return {n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,n_wbs1,n_hrs_trans,tdead_chop,tdead_data,tint_act};
}

// FPU Standby - CSA can be controlled - for use is chopper integrity checks.
// Ensures that chopper will be commanded to zero-position
// regardless of prime or redundant use.
block Band0_chopper_at_zero_block_aot HIFI 6296 {
    string band = "0"; // HIFI band
    string chop_loop = "CLOSE"; // Chopper Loop status
    string hbb_heater = "ON" in ["ON","OFF"]; //hot source on/off
}{
    IError("Band0_chopper_at_zero_block_aot is deprecated. Use Init_MSA_aot instead.");
}

// Flexible WBS attenuator tuning block with variable target
// Both polarizations are treated
block WBS_attenuators_block HIFI 6613 {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; //LO frequency
    string target_name = "normal"; // Name of target level
    bool oncold = false; // Whether we are on cold intead of HBB
}{
    // Get tuning goal
    double[] cresult = CalibrationReader("attenuator_levels",[target_name],band,lo_freq);
    double target_value = cresult[0];
    // Correct value in case of cold LOS instead of HBB
    if(oncold) {
        // Get involved temperatures
        double tsys = InterpolateTsys(band,1000.0 * lo_freq);
        {double,double} tloads = LoadTemperatures(band,1000.0 * lo_freq);
        double hotlevel = tsys + tloads{0};
        double coldlevel = tsys + tloads{1};
        target_value = target_value * coldlevel / hotlevel;
    } else {
        RotateChopper(band,lo_freq,"chop_hot");
        delay(1);
    }
    int tune_target = iround(100.0 * target_value);
    // Perform tuning
    Tune_WBS_aot(band,tune_target);
}

/////////////////////////////////////////////////////////////////
// Spectral scan in frequency switch without OFF calibration
// 
{string,double,double}[] procedure HifiSScanProcFSwitchNoRefSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_cycles = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // nherit from load-chop mode
    {string,double,double}[] retvalues = HifiSScanProcLoadChopNoRefSequencerInit(naifid,ra,dec,band,lo_freq,lo_freq_up,redundancy,effResolution,wbs1Used,wbs2Used,data_time,n_cycles,n_freq_point,load_interval,docommands);

    return retvalues;
}

//HIFI-COP-1.2-HRS_FT
obs HifiEng_HRS_FT_COP {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(HRS_FT_COP_proc_ops(prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            HRS_FT_COP_proc_ops(prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

//Chopper health check: step#3
procedure Chopper_FT3_COP_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Get chopper ON in closed-loop with voltage at rest position
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    Init_MSA_ops("0","CLOSE",0.0,result[0]{0},"ON",prime_or_redundant);
    Chopper_closed_loop_parameter_check_block_ops(prime_or_redundant);
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of OTF observing mode
{int,{int,int,int,int,int,int,int,int},double,double} procedure OTFmap_post_timing {
    {int,int,int,int,int,int,int,int} pre_timing = {10,1,12,13,21,10,50,0}; // pre_timing parameter list
    int[] telescopetimes = [300,180,2,2,40,10,20,21,0];
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int n_linesperscan = 1; // Number of lines between two OFFs
    int n_cover = 1; // Number of map coverages
    int load_interval = 1800; // load period = f(band,lo_freq,eff_resolution{1})
}{
    // Get all values from the pre_timing section
    int n_pp = pre_timing{0};
    int n_scans = pre_timing{1};
    int off_inttime = pre_timing{2};
    int off_pointing = pre_timing{3};
    int loadlength = pre_timing{4};
    int n_loadinterval = pre_timing{5};
    int initlength = pre_timing{6};
    int dangling = pre_timing{7};
    // Get all values from the telescope section
    int telinit = telescopetimes[1];
    // Initial slew time
    int slewtime = telescopetimes[6];
    // Slew time to OFF
    int longslew = telescopetimes[7];
    // Actual slew time for load slew
    int tturn = telescopetimes[5];
    // Turn around between lines
    int tline = telescopetimes[4];
    // Time in line
    int tend = telescopetimes[8];
    // Final deceleration time
    // The telescope slew can be a bit further than requested
    int line_inttime = n_pp * data_time;
    int line_time = line_inttime;
    if(tline != line_time) {
        if(tline < line_time) {
            CError("OTF scan length returned by telescope too short for instrument.");
        } else {
            line_time = tline;
        }
    }
    // Now compute the real scan time and the real load interval
    int scan_time = n_linesperscan * line_time + (n_linesperscan - 1) * tturn + 2 * slewtime + off_pointing;
    // Check for reasonable scan times
    if(scan_time > load_interval) {
        IError("Scan duration too long for required load period. " + "Reduce the map size or increase the step size.");
    }
    // Finally I can compute the actual load interval
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength + slewtime,scan_time);
    n_loadinterval = load_spacing / scan_time;
    n_loadinterval = imin(n_loadinterval,32);
    // Make sure that load slews occur at the same position in each coverage
    n_loadinterval = IMultiple(n_loadinterval,n_scans);
    // Compute duration of measurement
    int tdead = imax(loadlength,slewtime);
    int normal_scan_time = n_linesperscan * line_time + (n_linesperscan - 1) * tturn + 2 * slewtime + off_pointing;
    int load_scan_time = n_linesperscan * line_time + (n_linesperscan - 1) * tturn + slewtime + tdead + off_pointing;
    int n_tot = n_scans * n_cover;
    int n_load = n_tot / n_loadinterval;
    int maptime = (n_tot - n_load) * normal_scan_time + n_load * load_scan_time;
    // The initial time is no longer contained in the total time
    // int totaltime=imax(initlength,telinit);
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    int totaltime = maptime + off_pointing + dangling + tend;
    // Average dead and scan time for drift estimate
    double tscan = double(maptime) / double(n_tot);
    // Get pointing dead time, instrument dead time is added later
    double avdead = tscan - double(n_linesperscan * line_inttime + off_inttime);
    // show gyro-propagation messages
    GCPMessages(off_pointing,load_scan_time,tend);
    // Return all the times needed in the observing mode modules

    return {totaltime,{n_pp,n_scans,off_inttime,off_pointing,loadlength,n_loadinterval,initlength,dangling},tscan,avdead};
}

// Global total power spectroscopy for stability measurement, procedure
procedure Total_power_spectro_for_Stability_proc_fm {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integrations
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Compute data_time and n_switch using the wrapper
    int[] res = ConfigSlowChop(integ_time,"tp",band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_switch = n * res[1];
    //For stability measurement, the number of loop is a user input
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS. 
    // The deadtimes output is not used at ILT level.
    {double,double} dtimes = ConfigSpectroscopySlowChop(data_time,n_switch,"tp",band,0.0,backendreadoutparms,true);
    //Now start the long integration
    HIFI_Spectr_total_power_proc_fm(band,backend,data_time * n_switch);
}

{string,double,double}[] procedure HifiPointModeFSwitchSequencerInit {
    string modeName = "fs";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int n_switch_off = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF calibration cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    {double,double,double,double} phaselengths = FSwitchPhaseLengths(band,lo_freq,effResolution,oneGHzReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_switch_on_guess = imax(iceil(phaselengths{0} / (2.0 * double(data_time_guess))),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,2 * n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    new_data_time = MatchMinPointing(data_time_off_guess,data_time_off_range,2 * n_switch_off_guess);
    data_time_off_guess = new_data_time{0};
    data_time_off_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)}];

    return retvalues;
}

//HIFI investigation of diplexer with M1, mode
//Perform diplexer scans at a series of M1 values
//Frequencies and M1 values to use are pre-tabulated
obs HifiEng_diplexerscan_M1_COP {
    string band = "7b" in ["3b","7b"]; // HIFI band
    int testblock = 1 in [0,3]; //Test block for 3b
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Diplexerscan_M1_proc_fm_COP(band,testblock));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Diplexerscan_M1_proc_fm_COP(band,testblock);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double,double,double} procedure DoubleChop_deadtimes {
    string chopmode = "chop" in ["chop","lchop","fs"]; // chop mode
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval on ON
    int data_time_off = 4; // data dump interval on OFF
    int n_chop_on = 3; // number of chop cycles in one integration on ON
    int n_chop_off = 3; // number of chop cycles in one integration on OFF
    int n_load_on = 0; // number of integrations on ON -1
    int n_load_off = 0; // number of integrations on OFF -1
    double tdead = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get values for ON integration
    {double,double} tinst = GetInstDeadSlowChop(data_time,2 * n_chop_on,chopmode,band,lo_freq,backendreadoutparms);
    // dead time
    double tdeadint = double(data_time * 2 * n_chop_on) - tinst{0};
    // subtract dead times in switches
    // keep dead times between A-A and B-B in total dead time
    tdeadint = tdeadint - double(n_chop_on) * tinst{1};
    // add to total dead time
    double tdead_tot = tdead + double(n_load_on + 1) * tdeadint;
    double tswitch_on = tinst{1};
    double tphaseint_on = tinst{0} / double(2 * n_chop_on);
    // OFF integration
    tinst = GetInstDeadSlowChop(data_time_off,2 * n_chop_off,chopmode,band,lo_freq,backendreadoutparms);
    // dead time
    tdeadint = double(data_time_off * 2 * n_chop_off) - tinst{0};
    // subtract dead times in switches
    tdeadint = tdeadint - double(n_chop_off) * tinst{1};
    // add to total dead time
    tdead_tot = tdead_tot + double(n_load_off + 1) * tdeadint;
    double tswitch_off = tinst{1};
    double tphaseint_off = tinst{0} / double(2 * n_chop_off);
    // Return total dead time and the dead times in the two chops

    return {tdead_tot,tphaseint_on,tphaseint_off,tswitch_on,tswitch_off};
}

//Set HIFI to primary mode, mode
//In practice, it sets LOU in nominal mode with no channel selected
obs HifiEngSetIntoPrimary {
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(HifiIntoPrimary());
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // switch to nominal settings
            HifiIntoPrimary();
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure OTFDoubleChop_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int nlines = 20; // Number of lines in the map
    int npoints = 20; // Number of points in the map
    int n_switch_on = 1; // Supersamplingfactor
    int n_switch_off = 3; // Number of data dumps for the OFF integration time
    int n_scans = 2; // Number of OTF scans to cover the map
    int n_cycles = 1; // Number of map coverages
    bool fs = false; // whether frequency switch used
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double,double,double} tact = {10.0,4.9,4.9,0.05,0.05}; // Field of actual dead and integration times
}{
    double inttimeperonphase = tact{1};
    // Actual integration time in ON phase
    double inttimeperoffphase = tact{2};
    // Actual integration time in OFF phase
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    double idealnoise = idealvalues{1} * idealvalues{1};
    double obsnoise = noisevalues{0} * noisevalues{0};
    // rescale for map coverage
    idealnoise = idealnoise * double(npoints * nlines);
    double efficiency = idealnoise / obsnoise;
    // Compute the actual integration time
    double posinttime = double(n_cycles * nlines * npoints * 2 * n_switch_on) * inttimeperonphase;
    double posofftime = double((n_cycles * n_scans + 1) * 2 * n_switch_off) * inttimeperoffphase;
    int instrumenttime = iceil(double(n_cycles * n_scans) * tscan + double(2 * n_switch_off) * inttimeperoffphase);
    // Check total integration time
    double timeefficiency = (posinttime + posofftime) / double(totaltime);
    // Noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // Non-standard messages
    message("</p><p>");
    message("The observed map consists of " + nlines + " OTF lines, each covering " + npoints + " readout points.<br>");
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posofftime,timeefficiency,efficiency,relnoise,fs);
}

mode HifiManCmd_HIFI_Simulate_PU {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    mois_comment("Performing simulation of HIFI Peak-up packet report arrival");
    mois_tmcheck("The instrument can be in Standby I, Standby II or Primary modes in closed loop or open loop contexts for this test");
    //
    StartMode_block_ops();
    //
    //Simulate generation of PU report packet
    Simulate_PU_block_ops();
    StopMode_block_ops();
}

//  LCU configuration into NOMINAL mode for FSW, procedure
//  It allows to set LSU frequency to lo_freq, but effectively
//  using the chain settings of lo_freq_setting
//  Uses best guess D2 voltage from confgilcu table
procedure LCU_config_nominal_FSW_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency at which to set LSU
    double lo_freq_setting = 501.0; //LO frequency at which to take the settings
}{
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq_setting);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //Fetch best guess, and clip to blue max
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    drain2_v = min(result[0]{0},drain2_bluemax);
    //Send command: expect that we have already switched to NOMINAL
    //We set D2 to best guess and wait some time to stabilize chain temperature
    HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,config_lo_delay);
    //
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double} procedure SingleChop_deadtimes {
    string chopmode = "chop" in ["chop","lchop","fs"]; // chop mode
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval
    int n_chop = 3; // number of chop cycles in one integration
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get values for ON integration
    {double,double} tinst = GetInstDeadSlowChop(data_time,2 * n_chop,chopmode,band,lo_freq,backendreadoutparms);
    // only dead times in switches count as dead time;
    double tdead = double(data_time * 2 * n_chop) - tinst{0};
    // subtract dead times in switches
    // keep dead times between A-A and B-B in total dead time
    tdead = tdead - double(n_chop) * tinst{1};
    // add to total dead time
    double tswitch = tinst{1};
    double tphaseint = tinst{0} / double(2 * n_chop);
    // Return total dead time and the dead times in the two chops

    return {tdead,tphaseint,tswitch};
}

//HIFI-COP-2.1-IF-FBk1
procedure IF_FBk_COP_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string[] hrs_mode = ["wb1","wb1"];
    int integ_time = 600;
    string backend = "both";
}{
    //Switch-off LO
    LCU_switch_off_block_fm();
    //
    string[] chop1 = ["chop_M3","chop_M3","chop_M3","chop_M3","chop_cold"];
    string[] chop2 = ["chop_M3","chop_cold","chop_M3","chop_hot","chop_hot"];
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",[chop1[0],chop2[0]],band,0.0);
    int[] res = [0,0];
    //
    Init_MSA_fm(band,"CLOSE",lo_freq,"ON");
    //Use high biases
    result_d = ConfigurationReader("name_confilfpu",["bias_high_resistive_h","bias_high_resistive_v"],band,lo_freq);
    Mixerbias_block_fm(result_d[0]{0},result_d[1]{0});
    WBS_calib_fm(band);
    WBS_tune_proc_fm(band);
    HRS_config_block_fm(band,hrs_mode);
    HRS_tune_block_fm(band);
    //Reference measurement
    result_d = ConfigurationReader("name_confilfpu",[chop1[0],chop2[0]],band,0.0);
    res = Configure_Spectrometer_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    Spectro_slow_chop_block_fm(band,[result_d[0]{0},result_d[1]{0}],res,backend);
    //
    for(int i = 1 .. 4) {
        //
        result_d = ConfigurationReader("name_confilfpu",[chop1[i],chop2[i]],band,0.0);
        if(i == 2) {
            result_d[1]{0} = result_d[1]{0} - 0.5;
        }
        Spectro_slow_chop_block_fm(band,[result_d[0]{0},result_d[1]{0}],[integ_time * 2,1],backend);
    }
    // 
}

/////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing for a
// Spectral Scan DBS observing mode
// 
// We currently assume that each nodding motion is related to an
// instrument calibration. This may be an efficiency limitation if
// more calibration measurements are needed. Then the loop sequence
// should be changed.
// 
// This implementation assumes that the whole scan can be performed
// with a single pointing command. If the system temperature varies
// too much so that it cannot be compensated by a slight change of
// the redundancy, the scan has to be split into several calls of this
// mode.
//
{{int,int,int,int,int,int,int,int,int,bool,int,int,int},{int,double,double[],int[][],bool,double[],int,bool}} procedure FastSScanDBS_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq_low = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4; // Frequency scan redundancy
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 10 in [4,80]; // data dump interval
    int n_int = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_data = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed  
}{
    //////////////////////////////////////////////////////////////////////
    // Create composite readout structure for backends
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First check the group length 
    // The default frequency group length is given by n_freq_point.
    // It is derived in the sequencer using 
    //            GetFNoCalibLength(band,ref_freq);
    // For n_cycles>1 it has to be unity, everything else is rejected
    // We rely on the sequencer to determine the best group length
    if(n_cycles > 1 && n_freq_point > 1) {
        SError("Only frequency group length 1 allowed for cycle numbers > 1.");
    }
    // Get frequency grid characteristic parameters
    {int,double,double[],int[][],int,bool} fqparms = MakeFreqGrid(band,lo_freq_low,lo_freq_up,redundancy,0.0,n_freq_point);
    double reffreq = fqparms{1};
    double[] freqgrid = fqparms{2};
    int[][] grouporder = fqparms{3};
    // Process tuning level grid
    double[][] levelgrid = GetSScanLevelGrid(band,wbs1,wbs2,freqgrid,fqparms{0},grouporder);
    {bool,double[]} targets = TargetLevels(band,reffreq,levelgrid);
    bool retuning = targets{0};
    double[] targetgrid = targets{1};
    string reftarget = "";
    if(retuning) {
        reftarget = "sscan_normal";
    }
    {int,double,double[],int[][],bool,double[],int,bool} spectralparms = {fqparms{0},reffreq,freqgrid,grouporder,retuning,targetgrid,fqparms{4},fqparms{5}};
    //////////////////////////////////////////////////////////////////////
    // Get timing within the normal DBS observations
    // Fixed timings in the fast-chop mode
    int readouttime = data_time;
    int jitterdead = GetMaxTimeJitter(band,reffreq);
    // Integration time per frequency and pointing
    int inttime = readouttime * n_data;
    // Check chopper frequency
    CheckFastChopFrequency(band,reffreq,data_time,n_int,n_data);
    // Compute load integration time
    int load_datatime = GetStdLoadReadout(band,reffreq);
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,eff_resolution{0},load_datatime,backendreadoutparms));
    int readoutdead = FastChopReadoutDelay(band,reffreq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // The load interval
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    // Duration of initial set up
    // Staying at the same frequency makes no sense here. 
    // First frequency point
    double runningfreq = freqgrid[grouporder[0][0]];
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,runningfreq,hrs1,hrs2,wbs1{0},wbs2{0},"sscan_normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,true);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,runningfreq,false);
    }
    initlength = initlength + loadlength;
    // Tuning delays, big tune step has to be devisable by 2
    int bigtunestep = duration(HIFIRetuneFreq(band,reffreq,reftarget));
    // Correct for variation within the band
    int tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq);
    bigtunestep = bigtunestep + tunediff;
    if(n_freq_point > 1) {
        int smallstep = duration(HIFIChangeFreq(band,reffreq));
    } else {
        smallstep = bigtunestep;
    }
    // For double phases I can use the added jitterdead in both phases for tune
    int halftunestep = (bigtunestep - jitterdead + 1) / 2;
    // Check load_interval allowance
    int scan_time = 2 * inttime + bigtunestep;
    if(scan_time > load_spacing) {
        SError("Load interval of " + load_interval + "s is exceeded by nodding " + "period of " + scan_time + " s.");
    }
    // Rough estimate of the pointing time to issue a representative 
    // telescope command
    if(n_cycles > 1) {
        // How often do I have to perform a load slew
        int n_loadinterval = imax(load_interval / scan_time,1);
        // fit with n_cycles
        n_loadinterval = imin(n_loadinterval,n_cycles);
        n_loadinterval = IMultiple(n_loadinterval,n_cycles);
        // Pointing time
        int pointing = inttime + jitterdead;
    } else {
        n_loadinterval = 1;
        pointing = n_freq_point * inttime + (n_freq_point - 1) * smallstep + halftunestep + jitterdead;
    }
    int n_bchop = n_data;
    // recompute load length during slews in case of short integrations
    // This regime must be maintained in the post_timing
    if(n_loadinterval <= 1) {
        loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,false,eff_resolution{0},load_datatime,backendreadoutparms));
        loadlength = loadlength + readoutdead;
    }
    // No dangling needed in this mode - we stop halftunelength before telescope
    int dangling = 0;
    bool end_load = false;
    // Return all the times needed for telescope call and post_timing processing

    return {{inttime,pointing,readouttime,loadlength,jitterdead,load_spacing,bigtunestep,n_loadinterval,n_bchop,end_load,smallstep,initlength,dangling},spectralparms};
}

// Give sequence of frequency steps in a spectral scan mode within one group
int[][] procedure GetFrequencyGroupSteps {
    int groupsize = 3; // Number of frequencies in a group
}{
    // Compute limits
    int center = groupsize / 2;
    // First side stepping
    int[] firstside = [];
    int counter = 0;
    int i1 = center - 1;
    while(i1 >= 0) {
        firstside[counter] = i1;
        i1 = i1 - 1;
        counter = counter + 1;
    }
    i1 = groupsize - 1;
    while(i1 >= center) {
        firstside[counter] = i1;
        i1 = i1 - 1;
        counter = counter + 1;
    }
    // Second side stepping
    int[] secondside = [];
    counter = 0;
    i1 = center;
    while(i1 >= 0) {
        secondside[counter] = i1;
        i1 = i1 - 1;
        counter = counter + 1;
    }
    i1 = groupsize - 1;
    while(i1 > center) {
        secondside[counter] = i1;
        i1 = i1 - 1;
        counter = counter + 1;
    }
    int[][] fullseq = [firstside,secondside];

    return fullseq;
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of OTF load-chop observing mode
{int,int,int,int,bool,int,int} procedure OTFLoadChopNoRef_pre_timing {
    int nlines = 1; // Number of rows in the map
    int npoints = 10; // Number of data dumps per row
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int n_chop_on = 2 in [1,3600]; // number of half nu1-nu2-nu2-nu1 cycles per point
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    // jitter treatment is already taken into account by ValidMapSize
    // Compute parameters for the instrument timing
    int lineint = npoints * n_chop_on * 2 * data_time;
    int nlines_tot = nlines * n_cycles;
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Compute the scan size from the load interval
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,npoints * 8);
    // Here, we do not know the turn around-time yet. Ignored until post_timing
    int n_loadinterval = load_spacing / lineint;
    if(n_loadinterval < 1) {
        SError("Scan duration too long for load period. " + "Reduce the number of chop cycles.");
    }
    // Make sure that load slews occur at the same position in each coverage
    CheckReasonableLineNumber(nlines,true);
    n_loadinterval = IMultiple(n_loadinterval,nlines);
    // If no load required parameter has to be 0
    if(n_loadinterval > nlines_tot) {
        // Determine need for final load measurement
        double rest = double(nlines_tot % n_loadinterval) + 0.5;
        bool end_load_on = rest > 0.5001 * double(n_loadinterval);
    } else {
        if(n_loadinterval > nlines) {
            n_loadinterval = nlines;
        }
        // In all these cases a final load will be made anyway in regular pattern
        end_load_on = false;
    }
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,true);
    }
    initlength = initlength + loadlength;
    // Dangling load measurement not counted here, only dangling readout
    int dangling = readoutdead;
    // Return all the times needed in the observing mode modules
    // The holdlength parameter is abused for lineint here

    return {loadlength,load_spacing,n_loadinterval,lineint,end_load_on,initlength,dangling};
}

//LO parameter scan with HotCold measurement
//for Band 1a
procedure LCU1a_power_scan_with_Tsys {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4
    double lo_freq = 500.0 in [488.0,552.0]; //LO frequency
    double param_min = 1.0; //Min. of scanned parameter
    double param_max = 2.0; //Max. of scanned parameter
    double step_size = 0.1; //Step size
    string param_name = "D2"; //Code of scanned parameter: M1,M2,G1,G2,D1,D2.
    int integ_time = 4; //Total integration time in sec.
}{
    error("This module is obsolete: use LCU_power_scan_with_Tsys  instead");
}

{string,double,double}[] procedure HifiSScanModeFSwitchNoRefSequencerInit {
    string modeName = "fs-freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_cycles = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // nherit from load-chop mode
    {string,double,double}[] retvalues = HifiSScanProcLoadChopNoRefSequencerInit(naifid,ra,dec,band,lo_freq,lo_freq_up,redundancy,effResolution,wbs1Used,wbs2Used,data_time,n_cycles,n_freq_point,load_interval,docommands);

    return retvalues;
}

// Noise ratio from a two-phase observation
// 
double procedure TwoPhaseNoiseRatio {
    double x = 0.1; // value for integration time relative to Allan time
    double[] parameters = [0.3,2.5]; // Parameters: delay relative to Allan time, drift exponent 
}{
    // Assign parameters
    double d = parameters[0];
    double alpha = parameters[1];
    // get radiometric and drift noise
    double yn = TwoPhaseRadioNoise(x);
    double yd = TwoPhaseDrift(x,d,alpha);
    // Compute ratio
    double y = yd / yn;

    return y;
}

// Set the whole instrument from standby I to standby II mode
// This only switches on the WBS lasers
mode HifiManCmd_HIFI_standbyI_to_standbyII {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
    string chopper_loop = "OPEN" in ["OPEN","CLOSE"]; //chopper loop status
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    Mode_status_check_standby_I(chopper_loop,"up",prime_or_redundant);
    mois_comment("Set HIFI to standby mode II with " + laser_H + " switched on and chopper loop " + chopper_loop);
    StartMode_block_ops();
    //WBS stand-by with lasers ON
    mois_step("Switch WBS-H and WBS-V lasers ON");
    WBS_standby_block_ops("0",laser_H,laser_V);
    //
    StopMode_block_ops();
    Mode_status_check_standby_II(laser_H,laser_V,chopper_loop,"up",prime_or_redundant);
}

//  LCU configuration into NOMINAL mode with ALL inputs, procedure
procedure LCU_config_nominal_ALL_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    double m1_v = 7.0; // HL_M1_V
    double m2_v = 7.0; // HL_M2_V
    double m3_v = 0.0; // HL_M3_V
    double gate1_v = -0.5; // HL_Gate1_V
    double gate2_v = -0.1; // HL_Gate2_V
    double drain1_v = 2.0; // Drain1 voltage in V
    double drain2_v = 1.4; //Drain2 voltage in V
}{
    //Clear potential failure mode
    Set_LO_Nominal_block_fm();
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    int d2_step = iround(result[1]{0});
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command: expect that we have already switched to NOMINAL
    //Contrary to QM, the channel is automatically switched ON
    HIFI_Configure_LCU_ALL_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,config_lo_delay);
    //
}

////////////////////////////////////////////////////////////////////////
// Noise contributions from an asymmetric double difference observation
// This is still to be scaled by a factor T_cycle/(B_fluct*T_obs)
{double,double} procedure DoubleDifferenceNoiseValues {
    double x = 0.1; // value for integration time relative to Allan time
    double[] parameters = [1.0,1.0,0.8,0.8,0.05,0.3,2.5,5.0,2.5]; // Parameters: ratio of integration times, ratio of effective resolutions, delay in phase1, in phase 2, between phases relative to Allan time, drift exponents 
}{
    // Assign parameters
    double xrat = parameters[0];
    // ratio of integration times within B/A phases
    double resrat = parameters[1];
    // ratio of effective resolutions B/A phases
    double tpa = parameters[2];
    // total length of A pointing phase
    double tpb = parameters[3];
    // total length of B pointing phase
    double dpos = parameters[4];
    // dead time within A pointing relative to system Allan
    double d = parameters[5];
    // position switch dead time relative to differential Allan
    double alpha = parameters[6];
    // drift exponent of system Allan 
    double dallanrat = parameters[7];
    // ratio of differential to system Allan time
    double dalpha = parameters[8];
    // drift exponent of differential Allan 
    // Noise from first phase
    double yn = TwoPhaseRadioNoise(x);
    double yd = TwoPhaseDrift(x,dpos,alpha);
    // Normalize relative to total length of pointing phase
    double ysumn = yn * (2.0 * x + dpos) / tpa;
    double ysumd = yd * (2.0 * x + dpos) / tpa;
    // Noise from second phase
    // Rescale time scales
    double allan_scale = pow(1.0 / resrat,1.0 / alpha);
    // rescale Allan
    yn = TwoPhaseRadioNoise(x * xrat / allan_scale);
    yd = TwoPhaseDrift(x * xrat / allan_scale,dpos / allan_scale,alpha);
    // Noise scaled with resolution
    // Normalize relative to total length of pointing phase
    ysumn = ysumn + yn / (resrat * allan_scale) * (2.0 * x * xrat + dpos) / tpb;
    ysumd = ysumd + yd / (resrat * allan_scale) * (2.0 * x * xrat + dpos) / tpb;
    // Drift between phases
    yd = AsymmetricDrift(tpa / dallanrat,tpb / dallanrat,d / dallanrat,dalpha);
    // Compensate for different Allan time scaling
    yd = yd / dallanrat;
    ysumd = ysumd + yd;

    return {ysumn,ysumd};
}

// Detector heater control
block Heater_warm_fm HIFI 3241 {
    string band = "1a";
}{
    Start_block();
    //Get name of FPU configuration file
    {double,string}[] result_d = ConfigurationReaderWarm("name_confilfpu",["normal_heater_time_h","normal_heater_time_v","heater_delay_h","heater_delay_v","magnet_current_max_h","magnet_current_max_v"],band,0.0);
    double normal_heater_time_h = result_d[0]{0};
    //SCR-1385: set to 2sec
    double normal_heater_time_v = result_d[1]{0};
    //SCR-1385: set to 2sec
    int heater_delay_h = iround(result_d[2]{0});
    int heater_delay_v = iround(result_d[3]{0});
    //Magnets need to be switched to 0 prior to the deflux
    Hifi_HIFI_CH1_MX_MG_C($BBID,0.0);
    Hifi_HIFI_CV1_MX_MG_C($BBID,0.0);
    delay(1);
    //Start to send the pulse: command not yet available so we use single_cmd
    //Comment Hifi_HIFI_Set_SIS_heaters($BBID,normal_heater_time_h,normal_heater_time_v);
    //
    delay(1);
    Hifi_HIFI_HF_CH1_DHTR_C($BBID,normal_heater_time_h);
    delay(iceil(normal_heater_time_h / 1000.0) + 1);
    //Extra delay for cooling down temperature
    delay(heater_delay_h);
    Hifi_HIFI_HF_CV1_DHTR_C($BBID,normal_heater_time_v);
    delay(iceil(normal_heater_time_v / 1000.0) + 1);
    //Extra delay for cooling down temperature
    delay(heater_delay_v);
    //
    //Nominal values
    //Need a representative frequency: take keyfreq
    double[] result = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result[0];
    //
    result_d = ConfigurationReaderWarm("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
    double magnetcurrent_H = result_d[0]{0};
    double magnetcurrent_V = result_d[1]{0};
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnetcurrent_H);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnetcurrent_V);
    delay(1);
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of DBS-raster observing mode
{int,int,int,int,int,int,int,int,int,int,int,int,int} procedure DBSRaster_pre_timing {
    int nlines_tot = 1 in [1,100]; // Number of rows in the map
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_chop = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    // Is the map size an integer multiple of the scan size?
    CheckReasonableLineNumber(nlines_tot * npoints,false);
    int scansize = n_pointsperscan;
    if(scansize > nlines_tot * npoints) {
        SError("Scan size exceeds the total map size.");
    }
    if(nlines_tot * npoints % scansize != 0) {
        SError("Map size is no integer multiple of the scan size.");
    }
    int n_scans = nlines_tot * npoints / scansize;
    // Compute parameters for the instrument timing
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    int inttime = 2 * n_chop * data_time;
    int readouttime = data_time;
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,false);
    }
    initlength = initlength + loadlength;
    // compute the load interval in case of short scan_time
    int scan_time = inttime * scansize;
    int n_loadinterval = imax(load_interval / (2 * scan_time),1);
    // Special treatment for nodding_raster due to limitations in API
    // Split into loads per point or per multiple points
    if(scansize == 1 && n_loadinterval > n_cycles) {
        n_loadinterval = n_cycles * (n_loadinterval / n_cycles);
    }
    n_loadinterval = imin(n_loadinterval,n_cycles * n_scans);
    // Compare load interval and nodding interval
    // This determines the order of the loops
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    // load measurements within a single point integration
    int n_load = inttime / load_spacing;
    if(n_load >= 1 && scansize > 1) {
        SError("Number of points in one scan too large for load period.");
    }
    // Rough estimate of the pointing time - this is corrected
    // after the evaluation of the telescope command
    if(load_spacing > 2 * scan_time) {
        int n_seq = n_chop;
        int pointing = inttime + jitterdead;
    } else {
        // It is possible that a single point is short enough, but a scan
        // too long. Then everything is reduced to a single point.
        scansize = 1;
        n_scans = nlines_tot * npoints;
        n_seq = n_chop / (n_load + 1);
        inttime = 2 * n_seq * (n_load + 1) * data_time;
        pointing = inttime + (n_load + 1) * loadlength + jitterdead;
    }
    // dangling time given by readout dead time
    int dangling = readoutdead;
    int holdlength = jitterdead;
    // Return all the times needed for telescope call and post_timing processing

    return {inttime,pointing,readouttime,loadlength,holdlength,load_spacing,n_load,n_loadinterval,n_seq,n_scans,scansize,initlength,dangling};
}

///////////////////////////////////////////////////////////////////////////
// Building blocks
//
// Initialize all peakup settings
block HifiPeakupConfigure HIFI 6820 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    bool isH = true; // backend to use - polarization
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double stepsize = 0.0050; // Distance between subsequent points
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used, channel windows}
}{
    // Translate stepsize into 1/100 arcsec
    int scale = iround(stepsize * 360000.0);
    // Determine offsets
    if(isH) {
        double[] x = CalibrationReader("peakup",["offset_y_H","offset_z_H"],band,lo_freq);
        int offset_y = iround(x[0]);
        int offset_z = iround(x[1]);
    } else {
        x = CalibrationReader("peakup",["offset_y_V","offset_z_V"],band,lo_freq);
        offset_y = iround(x[0]);
        offset_z = iround(x[1]);
    }
    // Command offsets
    Hifi_HIFI_configure_peakup_r1($BBID,scale,scale,offset_y,offset_z);
    // Call procedure for slow-chop spectroscopy configuration
    ConfigureSpectroscopy(data_time,2 * n_cycle,"chop",band,lo_freq,backendreadoutparms);
    delay(1);
}

// WBS configuration with laser choice, block
// Both polarizations are treated
block WBS_config_w_laser_block_fm HIFI 3637 {
    string band = "1a"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
}{
    //Start_block();
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4","hwh_att_band3","hwh_att_band2","hwh_att_band1","hwh_att_in"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = iround(result_d[4]{0});
    int hwh_att_band3 = iround(result_d[5]{0});
    int hwh_att_band2 = iround(result_d[6]{0});
    int hwh_att_band1 = iround(result_d[7]{0});
    int hwh_att_in = iround(result_d[8]{0});
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4","hwv_att_band3","hwv_att_band2","hwv_att_band1","hwv_att_in"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = iround(result_d[4]{0});
    int hwv_att_band3 = iround(result_d[5]{0});
    int hwv_att_band2 = iround(result_d[6]{0});
    int hwv_att_band1 = iround(result_d[7]{0});
    int hwv_att_in = iround(result_d[8]{0});
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
}

//  LCU1b configuration into SAFE mode, procedure
procedure LCU1b_config_safe_proc_fm {
    string band = "1b"; // HIFI band
    double lo_freq = 600.0 in [566.0,633.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

// Needs the chopper in open-loop mode !!
block Chopper_openloop_scan_warm_block_fm HIFI 3794 {
    int scan_portion = 1 in [1,3]; //indicates which part of scans is to be done
}{
    //Start_block ();
    //Hard-coded RAW values for end stops and rest position 
    int low = 1298;
    //This is slightly further the low end-stop
    int high = 2548;
    //This is slightly further the high end-stop
    int zero = 2048;
    //This is the zero position
    int step = 50;
    //
    int chopper_pos = zero;
    //Scan from zero to end-stop high
    while(chopper_pos <= high) {
        if(scan_portion == 1) {
            HIFI_CPR_Chopper_Rot_RAW_proc_fm(chopper_pos);
            //Rotate chopper
            Hifi_HIFI_non_periodic_hk_FCU();
            //To get sent value
            delay(2);
        }
        chopper_pos = chopper_pos + step;
    }
    //Scan from end-stop high to end-stop low
    chopper_pos = high - step;
    while(chopper_pos >= low) {
        if(scan_portion == 2) {
            HIFI_CPR_Chopper_Rot_RAW_proc_fm(chopper_pos);
            //Rotate chopper
            Hifi_HIFI_non_periodic_hk_FCU();
            //To get sent value
            delay(2);
        }
        chopper_pos = chopper_pos - step;
    }
    //Scan from end-stop low to zero
    chopper_pos = low + step;
    while(chopper_pos <= zero) {
        if(scan_portion == 3) {
            HIFI_CPR_Chopper_Rot_RAW_proc_fm(chopper_pos);
            //Rotate chopper
            Hifi_HIFI_non_periodic_hk_FCU();
            //To get sent value
            delay(2);
        }
        chopper_pos = chopper_pos + step;
    }
}

//HIFI-COP-1.2-LO_FT for routine: uses single TM page TC
obs HifiEng_LO_FT_Routine {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(LO_FT_COP_proc_ops(band,prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            LO_FT_COP_proc_ops(band,prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

// Chop between internal and external cold loads, block
// We take 1 spectrum per phase.
block Stability_freqswitch_fm HIFI 3433 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integration pairs 
    int integ_time = 4; //Total (co-added) integration time of a phase in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    Start_block();
    //
    //We implement a special frequency switch spectroscopy for stability
    Freqswitch_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode);
}

// Get maximum frequency switch step length
double procedure GetMaxFreqThrow {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] throwlen = CalibrationReader("fsthrows",["maxfreqthrow"],band,lo_freq);

    return throwlen[0];
}

////////////////////////////////////
// Fast chop DBS raster observing mode
// 
{string,double,double}[] procedure HifiMappingProcFastDBSRasterSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,100]; // Number of rows in the map
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the raster line
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get the drift parameters to compute the drift noise
    {double,double} phaselengths = DBSPhaseLengths(band,lo_freq,effResolution,continuumDetection,oneGHzReference);
    // Compute derived quantities
    // Top down approach here
    int main_phase = iceil(phaselengths{0});
    // Arbitrary selection of data_time
    int data_time_guess = 20;
    // Combine points for n_switch=1
    int n_pointsperscan_guess = imin(imax(main_phase / data_time_guess,1),npoints * nlines);
    int n_pointsperscan_range = 1 - n_pointsperscan_guess;
    if(n_pointsperscan_range == 0) {
        n_pointsperscan_range = 1;
    }
    // remaining part for n_switch
    int n_switch_on_guess = main_phase / (n_pointsperscan_guess * data_time_guess) + 1;
    data_time_guess = main_phase / (n_pointsperscan_guess * n_switch_on_guess);
    // Check with data rate
    {int,double[]} dataparms = DataTaking(backendreadoutparms,8);
    int datalimit = 2 * dataparms{0};
    if(data_time_guess < datalimit) {
        data_time_guess = datalimit;
        n_switch_on_guess = 1;
    }
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // Chop phase length
    double phase_min = min(max(phaselengths{1},0.15),1.5);
    int n_int_on_guess = ifloor(double(data_time_guess) / (2.0 * phase_min));
    int n_int_on_range = -n_int_on_guess / 2;
    if(n_int_on_range == 0) {
        n_int_on_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_int_on",double(n_int_on_guess),double(n_int_on_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_pointsperscan",double(n_pointsperscan_guess),double(n_pointsperscan_range)}];

    return retvalues;
}

// Slow chop integration at OFF position ON-OFF-OFF-ON...
block HIFIHalfChopOffIntegration HIFI 6052 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_slow_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_M3","chop_M3right"],rates);
}

// HRS complete configuration, block
// Both polarizations are treated
block HRS_config_w_switch_block_fm HIFI 3713 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string[] switch = ["H","V"]; //HRS resolution code
}{
    //Start_block();
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = switch[0];
    double hrsH_ATT_U1 = result[1]{0};
    double hrsH_ATT_L1 = result[2]{0};
    double hrsH_ATT_U2 = result[3]{0};
    double hrsH_ATT_L2 = result[4]{0};
    double hrsH_ATT_U3 = result[5]{0};
    double hrsH_ATT_L3 = result[6]{0};
    double hrsH_ATT_U4 = result[7]{0};
    double hrsH_ATT_L4 = result[8]{0};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = switch[1];
    double hrsV_ATT_U1 = result[1]{0};
    double hrsV_ATT_L1 = result[2]{0};
    double hrsV_ATT_U2 = result[3]{0};
    double hrsV_ATT_L2 = result[4]{0};
    double hrsV_ATT_U3 = result[5]{0};
    double hrsV_ATT_L3 = result[6]{0};
    double hrsV_ATT_U4 = result[7]{0};
    double hrsV_ATT_L4 = result[8]{0};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_ATT_U1,hrsH_ATT_L1,hrsH_ATT_U2,hrsH_ATT_L2,hrsH_ATT_U3,hrsH_ATT_L3,hrsH_ATT_U4,hrsH_ATT_L4,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
    // 
    //delay(hrs_config_delay);
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsV_ATT_U1,hrsV_ATT_L1,hrsV_ATT_U2,hrsV_ATT_L2,hrsV_ATT_U3,hrsV_ATT_L3,hrsV_ATT_U4,hrsV_ATT_L4,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
    // 
    delay(hrs_config_delay);
    ////////////////////////////////////////////////////////////////////
    //Now Configure blocks
    //H-polar
    result = ConfigurationReader(hrs_filename_h,["hrh_block_1","hrh_block_2","hrh_block_3","hrh_block_4","hrh_block_5","hrh_block_6","hrh_block_7","hrh_block_8"],band,0.0);
    string hrh_block_1 = result[0]{1};
    string hrh_block_2 = result[1]{1};
    string hrh_block_3 = result[2]{1};
    string hrh_block_4 = result[3]{1};
    string hrh_block_5 = result[4]{1};
    string hrh_block_6 = result[5]{1};
    string hrh_block_7 = result[6]{1};
    string hrh_block_8 = result[7]{1};
    //
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrh_block_1,hrh_block_2,hrh_block_3,hrh_block_4,hrh_block_5,hrh_block_6,hrh_block_7,hrh_block_8);
    //delay(hrs_config_delay);
    //
    //V-polar
    result = ConfigurationReader(hrs_filename_v,["hrv_block_1","hrv_block_2","hrv_block_3","hrv_block_4","hrv_block_5","hrv_block_6","hrv_block_7","hrv_block_8"],band,0.0);
    string hrv_block_1 = result[0]{1};
    string hrv_block_2 = result[1]{1};
    string hrv_block_3 = result[2]{1};
    string hrv_block_4 = result[3]{1};
    string hrv_block_5 = result[4]{1};
    string hrv_block_6 = result[5]{1};
    string hrv_block_7 = result[6]{1};
    string hrv_block_8 = result[7]{1};
    //
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrv_block_1,hrv_block_2,hrv_block_3,hrv_block_4,hrv_block_5,hrv_block_6,hrv_block_7,hrv_block_8);
    //
    //Wait delay to allow all setting to be configured
    delay(hrs_config_delay);
}

//////////////////////////////////////////////////////////
// Commanding procedures: 1:1 copy from normal raster
// Procedure to generate the instrument commands for the DBS raster mode
procedure HalfDBSRaster_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size
    int n_seq = 1; // Number of continuous chop cycles
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF cycles 
    int n_pointsperscan = 1; // Number of points measured before moving to the second pointing phase
    int n_loadinterval = 10; // number of nods before a load measurement
    int n_load = 0; // additional load measurements in one pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,10,0,10,20,21,0,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    bool iscross = false; // Whether we use a cross instead of a raster
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get all values from the telescope section  
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // Count phases by hand to allow simultaneous usage by Raster and Cross
    int iphase = 0;
    // There is no nod counter in the return values - count this by hand
    int inod = 0;
    // Do I have to make loads in short nods and subsequent holds?
    if(iscross) {
        bool holdforload = n_pointsperscan > 1;
    } else {
        holdforload = n_pointsperscan == 1 && n_loadinterval > n_cycles;
    }
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
            iphase = iphase + 1;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            // The use of n_load differs by 1 from the other observing modes here
            for(int i1 = 1 .. n_load - 1) {
                HIFIHalfChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle 
            HIFIHalfChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            // n_pointsperscan=1, n_loadinterval > n_cycles
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == 1) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
            // Update phase counter
            iphase = iphase + 1;
        }
        // Second pointing phase
        if(state[0] == 7) {
            // second nod position
            HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            for(int i2 = 1 .. n_load - 1) {
                HIFIHalfChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle 
            HIFIHalfChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == 1) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
            // Update phase counter
            iphase = iphase + 1;
        }
        // Load nod
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
        }
        // Hold
        if(state[0] == 6) {
            // finished shift of instrument operations relative to pointing command
            runintostate = false;
        }
        // Final load
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

//HIFI measurement of HEB spectra variation vs Imix, procedure
//Takes spectra over the full Vd2 range
procedure HEB_Spectra_vs_Imix_proc_fm_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    bool lo_chain_switch = true; //Whether the chain is already switched on
    int testtime = 900; //total time we want to spend on testing
}{
    //The same approach as for Vector_scan_BLUE_LIMIT_block_fm is followed,
    //except that spectra are taken at each Vd2 step.
    //
    //Variable for stabilization measurement
    string chopmode = "slowchop";
    double chop_phase = 1.0;
    //not used here
    string backend = "both";
    int integ_time = 4;
    string[] hrs_mode = ["wb1","wb1"];
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //
    //
    int starttime = time();
    //Get the parameters used for the scan
    string tab = "config_HEB_Imix_spec.config";
    double bandnb = GetBandCode(band);
    double lo_freq = dlookup(tab,"" + iceil(bandnb),"lofreq");
    //Configure FPU at that frequency
    Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
    //
    int warmup_time = 860;
    if(lo_chain_switch) {
        //in this case we will have drift on top of the Vd2 scan
        LCU_switchon_proc_fm(band);
        LO_tuning_block_fm(band,lo_freq);
        //using best-guess Vd2
        int intermediatetime = warmup_time - (time() - starttime);
        int n = intermediatetime / integ_time / 2;
        //number of frames for one phase
        //During the next ~15min, take data as a stability measurement
        Proc_stability_intcold_inthot(band,n,hrs_mode,integ_time,backend,chopmode,chop_phase);
    }
    //
    //Now system is stable but likely un-pumped again
    //This is the perfect point to re-adjust the WBS attenuators
    WBS_tune_proc_fm(band);
    //Perform vector scan with spectra within BLUE limits at that frequency
    Vector_scan_BLUE_LIMIT_w_spectra_proc_COP(band,lo_freq,testtime);
}

/////////////////////////////////////////////////////////////////
// Spectral scan in frequency switch with OFF calibration
// 
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiSScanProcFSwitch {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    bool refSelected = true; // Dummy parameter required by HSPOT
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_switch_off = 1 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - Frequency Switch Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = SScanFSwitch_pre_timing(band,lo_freq,lo_freq_up,redundancy,freq_throw,effResolution,hr1,hr2,wb1,wb2,data_time,data_time_off,n_switch_on,n_switch_off,n_freq_point,n_cycles,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    int n_total = groupnumber * n_cycles;
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,reffreq,pre_timing{0},n_total);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},double,double,double} post_timing = SScanDoubleChop_post_timing(pre_timing{0},telescopetimes,n_freq_point,groupnumber,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,reffreq,post_timing{1},n_total);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    // normal pre_timing values
    int on_inttime = post_timing{1}{0};
    int off_inttime = post_timing{1}{1};
    int n_loadinterval = post_timing{1}{7};
    int n_long_on = post_timing{1}{8};
    int n_long_off = post_timing{1}{9};
    int shiftlength = post_timing{1}{5};
    int initlength = post_timing{1}{14};
    bool final_load = post_timing{1}{12};
    // efficiency parameters
    double avnumchop_on = post_timing{2};
    double avnumchop_off = post_timing{3};
    double tscan = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        SScanFSwitch_commanding(band,reffreq,freq_throw,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,data_time_off,n_switch_on,n_switch_off,n_long_on,n_long_off,n_cycles,n_total,n_loadinterval,final_load,startobs,telescopetimes,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = SScanDoubleChop_deadtimes("fs",band,reffreq,hr1,hr2,wb1,wb2,n_freq_point,data_time,data_time_off,n_switch_on,n_switch_off,n_long_on,n_long_off,n_cycles,avnumchop_on,avnumchop_off,tscan);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanFSwitch_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,on_inttime,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    SScanDoubleChop_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_freq_point,n_cycles,groupnumber * n_freq_point,avnumchop_on,avnumchop_off,true,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

procedure IError {
    string errormessage = "Bad parameter combination."; // Error message
}{
    string fullmessage = "Invalid input parameter setting:<br>" + errormessage + "<br>Please, change your AOR parameters.";
    error(fullmessage);
}

// Wrapper for fixed instrument configurations.
//
// This is used for the COLD instrument - in-orbit configuration
//
{double,string}[] procedure ConfigurationReader {
    string topicname = "name_confilfpu"; // Name of entry in master file
    string[] objectnames = ["bias_standby_h"]; // Names of calibration objects to be read
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    string mainmasterfile = "configuration_masterfile";
    {double,string}[] retvalues = FlexibleConfigurationReader(mainmasterfile,topicname,objectnames,band,lo_freq);

    return retvalues;
}

// Very fast sampling stability measurement, procedure
// Uses only the HRS in wb mode
block Stability_fast_block_fm HIFI 3436 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int n = 100; //Number of samples to be measured
    double sampling_rate = 2.0 in [1.0,6.0]; //Sampling rate: 2 (2 HRS-H + 2 HRS-V), 3 (HRS-H + HRS-V),  4 (2 HRS-H or 2 HRS-V) or 6 (1 HRS-H or 1 HRS-V) Hz
    string hrs_polarization = "H" in ["H","V","B"]; //HRS polarization: selection works only for 4 and 8 Hz
}{
    Start_block();
    //
    //Derive number of n_wbs_start necessary to get all dumps.
    //We assume WBS loops 65 sec long max.
    int max_wbs_time = 65000;
    int total_time = n * 1000 / iround(sampling_rate);
    int n_loop = 20;
    int loop = 20;
    for(int i = 1 .. loop - 1) {
        //debug_print(i);
        if(total_time <= max_wbs_time * (loop - i)) {
            //debug_print(max_wbs_time*(loop-i));
            n_loop = loop - i;
        }
    }
    //
    // Get fixed parameters from configuration and calibration files
    // Command jitter time is the default delay 
    {double,string}[] result = ConfigurationReader("name_delays",["add_jitter"],band,0.0);
    int add_jitter = iround(result[0]{0});
    // Additional delays in the readout loops - given in OBS user manual
    result = ConfigurationReader("name_delays",["add_hrs","add_wbs","add_jitter","wbs_init","wbs_chunksize","tacc_add","hrs_phase"],band,0.0);
    int add_hrs = iround(result[0]{0});
    int add_wbs = iround(result[1]{0});
    int wbs_init = iround(result[3]{0});
    int wbs_chunksize = iround(result[4]{0});
    int tacc_add = iround(result[5]{0});
    int hrs_phase = iround(result[6]{0});
    // HRS standard phase length
    //
    //Fetch default parameters
    result = ConfigurationReader("name_confilspec",["del_hrs","del_wbs","t_acc_wbs","t_acc_hrs","n_wbs_integr","n_hrs_integr","n_wbs_start","r_hrs","wbsh_offset1","wbsh_width1","wbsh_offset2","wbsh_width2","wbsh_offset3","wbsh_width3","wbsh_offset4","wbsh_width4","wbsv_offset1","wbsv_width1","wbsv_offset2","wbsv_width2","wbsv_offset3","wbsv_width3","wbsv_offset4","wbsv_width4","hrs_rshift","wbs_rshift","hrsh_sel","hrsv_sel","wbs_packing"],band,0.0);
    //
    int del_hrs = iround(result[0]{0});
    int del_wbs = iround(result[1]{0});
    int t_acc_wbs = iround(result[2]{0});
    int t_acc_hrs = iround(result[3]{0});
    int n_wbs_integr = iround(result[4]{0});
    int n_hrs_integr = iround(result[5]{0});
    int n_wbs_start = n_loop;
    int r_hrs = iround(result[7]{0});
    int wbsh_offset1 = 0;
    int wbsh_width1 = 0;
    int wbsh_offset2 = 2048;
    int wbsh_width2 = 0;
    int wbsh_offset3 = 4096;
    int wbsh_width3 = 0;
    int wbsh_offset4 = 6144;
    int wbsh_width4 = 0;
    int wbsv_offset1 = 0;
    int wbsv_width1 = 0;
    int wbsv_offset2 = 2048;
    int wbsv_width2 = 0;
    int wbsv_offset3 = 4096;
    int wbsv_width3 = 0;
    int wbsv_offset4 = 6144;
    int wbsv_width4 = 0;
    int hrs_rshift = iround(result[24]{0});
    int wbs_rshift = iround(result[25]{0});
    int hrsh_sel = 192;
    //1100000 = 1U and 2U
    int hrsv_sel = 192;
    //1100000 = 1U and 2U
    string wbs_packing = "24_bits_format";
    //result[28]{1};
    //
    t_acc_wbs = (total_time - wbs_init) / n_loop - add_jitter - add_wbs - del_wbs;
    // discretize in 10ms chunks
    int nchunk = (t_acc_wbs - tacc_add) / wbs_chunksize;
    t_acc_wbs = nchunk * wbs_chunksize + tacc_add;
    //WBS time need to be at least 1 sec
    if(t_acc_wbs < 1000) {
        t_acc_wbs = 1005;
    }
    r_hrs = iceil(double(t_acc_wbs) * sampling_rate / 1000.0);
    t_acc_hrs = (t_acc_wbs - add_jitter) / r_hrs - del_hrs - add_hrs;
    //
    //Adapt parameters to our case
    //Currently  2Hz and polar = B: 2 subbands and 2 polar
    // Science data: n_polar*(n_band*2*258*24+1376+3*272)
    int allbits = 2 * (2 * 2 * 258 * 24 + 1376 + 3 * 272);
    string backend = "hrs";
    if(sampling_rate == 3.0) {
        //polar = B: 1 band, 2 polar
        allbits = 2 * (2 * 258 * 24 + 1376 + 3 * 272);
        hrsh_sel = 128;
        //10000000 = 1U only
        hrsv_sel = 128;
        //10000000 = 1U only
        backend = "hrs";
    }
    if(sampling_rate == 4.0) {
        if(hrs_polarization == "B") {
            //forbidden case
            error("You cannot use this speed with both HRS - try 3Hz");
        }
        if(hrs_polarization == "H") {
            //2 bands, 1 polar
            allbits = 2 * 2 * 258 * 24 + 1376 + 3 * 272;
            hrsh_sel = 192;
            //11000000 = 1U and 2U
            hrsv_sel = 0;
            //00000000 = no subband
            backend = "hrsFast";
        }
        if(hrs_polarization == "V") {
            //2 bands, 1 polar
            allbits = 2 * 2 * 258 * 24 + 1376 + 3 * 272;
            hrsh_sel = 0;
            //00000000 = no subband
            hrsv_sel = 192;
            //11000000 = 1U and 2U
            backend = "hrsFast";
        }
    }
    if(sampling_rate > 4.0) {
        //only one band, one polarization
        if(hrs_polarization == "B") {
            //forbidden case
            error("You cannot use this speed with both HRS - try 3Hz");
        }
        allbits = 2 * 258 * 24 + 1376 + 3 * 272;
        backend = "hrsFast";
        //If polar = H
        hrsh_sel = 128;
        //10000000 = 1U only
        hrsv_sel = 0;
        //00000000 = no subband
        if(hrs_polarization == "V") {
            hrsh_sel = 0;
            //00000000 = no subband
            hrsv_sel = 128;
            //11000000 = 1U only
        }
    }
    //
    //Configure integration to be done
    Hifi_HIFI_config_spectroscopy($BBID,n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,wbsh_offset1,wbsh_width1,wbsh_offset2,wbsh_width2,wbsh_offset3,wbsh_width3,wbsh_offset4,wbsh_width4,wbsv_offset1,wbsv_width1,wbsv_offset2,wbsv_width2,wbsv_offset3,wbsv_width3,wbsv_offset4,wbsv_width4,hrs_rshift,wbs_rshift,hrsh_sel,hrsv_sel,wbs_packing);
    //
    //Compute delay
    int delay_total_power = iceil(double(total_time) / 1000.0);
    //Prepare data-rate computation
    // Clean  HK treatment for controlled data rates
    {string,int,double,double,double,double} hkparms = PeriodicHKParms("fast");
    // HK data: stdrate=7744+864+2*272, IF packets=2*(592+272)
    int allhkbits = 1782;
    double hkrate = hkparms{3} + double(allhkbits) / double(t_acc_hrs) * 1000.0;
    double sciencerate = double(allbits) / double(t_acc_hrs) * 1000.0;
    // set data rates
    ess_hk_data_rate(hkparms{5} / 1024.0);
    non_ess_hk_data_rate(hkrate / 1024.0);
    data_rate(sciencerate / 1024.0);
    //start integration
    Hifi_HIFI_Spectr_total_power($BBID);
    Apply_Total_Power_delay(delay_total_power,band,backend);
    // reset data rates
    non_ess_hk_data_rate(hkparms{3} / 1024.0);
    data_rate(0.0);
    //Apply delay: add one second for security
    delay(1);
    //
}

//////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the observing mode
{double,double,double,double,double} procedure SScanLoadChop_noisecomputer {
    string band = "4a"; // HIFI band
    double reffreq = 978300.0; // Reference LO frequency in scan center
    int nfreq = 4; // Number of frequency points per IF
    bool dsb = true; // Both sidebands covered
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    int on_inttime = 16; // Integration time per ON phase
    int off_inttime = 16; // Integration time per OFF phase
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double,double,double} tact = {10.0,4.9,4.9,0.05,0.05}; // Field of actual dead and integration times
}{
    // spectral scans always use the full bandwidth for reference
    bool oneGHzReference = false;
    // Call load-chop noise computer
    {double,double,double,double,double} noisevalues = LoadChop_noisecomputer(band,reffreq,eff_resolution,oneGHzReference,on_inttime,off_inttime,n_cycles,tscan,tact);
    // Correct for multiple frequencies
    double multiplier = sqrt(1.0 / double(nfreq));
    noisevalues{0} = noisevalues{0} * multiplier;
    noisevalues{1} = noisevalues{1} * multiplier;
    // Check for double sideband coverage
    if(dsb) {
        // Combine LSB-USB noise
        // In spectral scans we have only a combined noise temperature for both
        // sidebands, so that the USB/LSB separation is not used
        double[] gssb = InterpolateGssb(band,reffreq);
        double usbnoise_lores = noisevalues{0} / sqrt(1.0 + gssb[1] / gssb[0] * (gssb[1] / gssb[0]));
        double usbnoise_hires = noisevalues{1} / sqrt(1.0 + gssb[1] / gssb[0] * (gssb[1] / gssb[0]));
        double lsbnoise_lores = usbnoise_lores;
        double lsbnoise_hires = usbnoise_hires;
    } else {
        // Get single sideband noise equivalent
        usbnoise_lores = noisevalues{0};
        usbnoise_hires = noisevalues{1};
        lsbnoise_lores = noisevalues{2};
        lsbnoise_hires = noisevalues{3};
    }
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noisevalues{4}};
}

//  LCU configuration into NOMINAL mode, procedure
//  Uses best guess D2 voltage from confgilcu table
procedure LCU_config_nominal_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
}{
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //Fetch best guess, and clip to blue max
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    drain2_v = min(result[0]{0},drain2_bluemax);
    //Send command: expect that we have already switched to NOMINAL
    //We set D2 to best guess and wait some time to stabilize chain temperature
    HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,config_lo_delay);
    //
}

//  LCU4b configuration into SAFE mode, procedure
procedure LCU4b_config_safe_proc_fm {
    string band = "4b"; // HIFI band
    double lo_freq = 1100.0 in [1056.0,1113.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

// Stability test, procedure, no IF1
procedure Proc_stability_noIF1 {
    string band = "1a"; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string mixer_polarization = "B" in ["H","V","B"]; //Polarization: H, V, or both (B) 
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Sets FPU with no IF1
    Init_noIF1_fm(band,mixer_polarization);
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        //Configure and tune backends
        WBS_tune_proc_fm(band);
        //WBS_config_min_att_w_laser_block_fm(band,laser_H,laser_V);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        //Configure and tune backends
        HRS_config_min_att_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration: done later
    //Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);	//2 sec. integration
    //
    Stability_noIF1_fm(band,n,integ_time,backend,hrs_mode);
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
}

// WBS configuration with laser choice, block
// Used to switch on laser
block WBS_config_w_laser_block_ops HIFI 7637 {
    string band = "0"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
}{
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4","hwh_att_band3","hwh_att_band2","hwh_att_band1","hwh_att_in"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = iround(result_d[4]{0});
    int hwh_att_band3 = iround(result_d[5]{0});
    int hwh_att_band2 = iround(result_d[6]{0});
    int hwh_att_band1 = iround(result_d[7]{0});
    int hwh_att_in = iround(result_d[8]{0});
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4","hwv_att_band3","hwv_att_band2","hwv_att_band1","hwv_att_in"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = iround(result_d[4]{0});
    int hwv_att_band3 = iround(result_d[5]{0});
    int hwv_att_band2 = iround(result_d[6]{0});
    int hwv_att_band1 = iround(result_d[7]{0});
    int hwv_att_in = iround(result_d[8]{0});
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    mois_tmcheck("Check that parameter HWH_Laser1_S is " + hwh_laser1_s);
    mois_tmcheck("Check that parameter HWH_Laser2_S is " + hwh_laser2_s);
    mois_tmcheck("Check that parameter HWV_Laser1_S is " + hwv_laser1_s);
    mois_tmcheck("Check that parameter HWV_Laser2_S is " + hwv_laser2_s);
}

//////////////////////////////////////////////////////////////////
// Procedure to compute detailed pre timing for the version of the
// frequency switch mode without baseline measurement
// 
{int,int,int,int,int,int,bool,int,int} procedure FSwitchNoRef_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_chop_on = 2 in [1,3600]; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    /////////////////////////////////////////////////////////////////////
    CheckLOFrequencies(band,lo_freq + min(freq_throw,0.0),lo_freq + max(freq_throw,0.0));
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    CheckFswOutOfBand(band,lo_freq,freq_throw,backendreadoutparms);
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    // Compute parameters for the instrument timing
    int on_inttime = 2 * n_chop_on * data_time;
    // compute load integration time
    int loadlength = duration(DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Compare load interval with duration of the observation
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    int n_load_on = on_inttime / load_spacing;
    // This determines the order of the loops
    if(load_spacing > 2 * on_inttime) {
        int n_per_on = n_chop_on;
        bool end_load_on = false;
        int on_pointing = on_inttime + jitterdead;
    } else {
        n_per_on = n_chop_on / (n_load_on + 1);
        if(n_per_on < 1) {
            SError("FS phase length on source too long relative to load period.");
        }
        end_load_on = true;
        on_inttime = 2 * n_per_on * (n_load_on + 1) * data_time;
        on_pointing = on_inttime + n_load_on * loadlength + jitterdead;
    }
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFIFsw(band,lo_freq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,true);
    }
    initlength = initlength + loadlength;
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed for telescope call and post_timing processing

    return {on_inttime,on_pointing,loadlength,load_spacing,n_per_on,n_load_on,end_load_on,initlength,dangling};
}

// Compute total power delay necessary for integration, procedure
procedure Apply_Total_Power_delay {
    int total_time = 12; //single readout time * n_wbs_start
    string band = "1a"; // HIFI band
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Packet transfer time
    {double,string}[] result = ConfigurationReader("name_delays",["wbs_transfer_delay"],band,0.0);
    //
    int wbs_packet_transfer_time = iround(result[0]{0});
    //
    //In case less channels are used, one must adapt the transfer time
    if(backend == "hrs" || backend == "wbs") {
        //wbs_packet_transfer_time = 0;	//3000;
    }
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        //expect half backend
        //wbs_packet_transfer_time = 0;	//2000;
    }
    //
    //Compute delay
    int delay_total_power = total_time + wbs_packet_transfer_time / 1000;
    //debug_print("Total power delay: " + delay_total_power + " sec");
    //
    //Apply delay
    delay(delay_total_power);
    //
}

// WBS linearity test, loop on main attenuator, block
block FT_WBS_linearity HIFI 3708 {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //
    //Set zero and comb off
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_OFF");
    delay(2);
    //
    //Initial configuration: overall attenuators set to max., individual attenuators to 0
    //H-Polarization
    //
    {double,string}[] result = ConfigurationReader("name_configwbs",["hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result[0]{0});
    string hwh_latchup_s = result[1]{1};
    int hwh_att_band4 = 0;
    int hwh_att_band3 = 0;
    int hwh_att_band2 = 0;
    int hwh_att_band1 = 0;
    int hwh_att_in = 16;
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result[0]{0});
    string hwv_latchup_s = result[1]{1};
    int hwv_att_band4 = 0;
    int hwv_att_band3 = 0;
    int hwv_att_band2 = 0;
    int hwv_att_band1 = 0;
    int hwv_att_in = 16;
    //
    //Loop on overall attenuators
    for(int i = 0 .. 15) {
        // Change the value of the main attenuator
        //========================================
        hwh_att_in = hwh_att_in - 1;
        hwv_att_in = hwv_att_in - 1;
        // Set WBS
        //========
        //0dB attenuation on individual attenuators
        hwh_att_band4 = 0;
        hwh_att_band3 = 0;
        hwh_att_band2 = 0;
        hwh_att_band1 = 0;
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        hwv_att_band4 = 0;
        hwv_att_band3 = 0;
        hwv_att_band2 = 0;
        hwv_att_band1 = 0;
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
        //
        //1dB attenuation on individual attenuators
        hwh_att_band4 = 1;
        hwh_att_band3 = 1;
        hwh_att_band2 = 1;
        hwh_att_band1 = 1;
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        hwv_att_band4 = 1;
        hwv_att_band3 = 1;
        hwv_att_band2 = 1;
        hwv_att_band1 = 1;
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
    }
    //Set att. to max.
    WBS_config_proc_max_att_w_laser_fm(band,laser_H,laser_V);
    //
}

//Startblock
procedure Start_block {
}{
    //These are ILT-EGSE commands, not ruled by the 2TC/sec.
    //HifiIltEgse_FPU_set_BB_ID($BBID);
    //HifiIltEgse_PDU_set_BB_ID($BBID);
    //SpireIltEgse_QCC_SETBBID($BBID);
    //delay(1);
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    Hifi_HIFI_non_periodic_hk_FCU();
    delay(1);
}

// Stability test, procedure, case 1
// Measurement of internal hot only
procedure Proc_stability_inthot {
    string band = "1a"; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string obsmode = "tp" in ["fastchop","tp"]; //tp or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    //
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //Look at HBB
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        //Configure and tune backends
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration: done later
    //Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);	//2 sec. integration
    //
    Stability_inthot_fm(band,n,integ_time,backend,hrs_mode,obsmode,chop_phase);
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
}

/////////////////////////////////////////////////////////////////
// Second step of timing computation after telescope behaviour
// is known -  Spectral Scan frequency switch observing mode
// without baseline measurement
// 
{int,{int,int,int,int,int,int,bool,int,int},double,double} procedure SScanChopNoRef_post_timing {
    {int,int,int,int,int,int,bool,int,int} pre_timing = {16,16,21,1800,2,0,false,50,0}; // pre_timing parameter list
    int[] telescopetimes = [300,180,0];
}{
    // Get all values from the pre_timing section
    int on_inttime = pre_timing{0};
    int on_pointing = pre_timing{1};
    int loadlength = pre_timing{2};
    int load_spacing = pre_timing{3};
    int n_per_on = pre_timing{4};
    int n_load_on = pre_timing{5};
    bool end_load_on = pre_timing{6};
    int initlength = pre_timing{7};
    int dangling = pre_timing{8};
    // Get all values from the telescope section
    int telinit = telescopetimes[1];
    // Initial slew time
    int tend = telescopetimes[2];
    // Final deceleration time
    // No further computations needed
    // Dangling readout only applies if there is no dangling load in this case
    if(n_load_on > 0) {
        dangling = 0;
    }
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    // Compute total duration
    int totaltime = on_pointing + dangling + tend;
    double tscan = double(on_inttime) / double(n_per_on * imax(n_load_on,1));
    // No telescope dead time in fine pointing
    double tdead = 0.0;
    // show gyro-propagation messages
    // no gyro-propagation for fine_pointing
    GCPMessages(0,on_pointing,tend);
    // Return all the times needed in the observing mode modules

    return {totaltime,{on_inttime,on_pointing,loadlength,load_spacing,n_per_on,n_load_on,end_load_on,initlength,dangling},tscan,tdead};
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure LoadChop_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval limited by the data rates
    int data_time_off = 4; // data dump interval on OFF
    int n_per_on = 2; // number of half load-sky-sky-load cycles on ON
    int n_per_off = 2; // number of half load-sky-sky-load cycles on OFF
    int n_loadinterval = 1; // number of nods before a load measurement
    int n_load_on = 0; // additional load measurements in ON pointing phase
    int n_load_off = 0; // additional load measurements in OFF pointing phase
    bool end_load_on = false; // Need for load after ON pointing phase
    bool end_load_off = false; // Need for load after OFF pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    int shiftlength = 0; // Shift of the loop start relative to the pointing
}{
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] onrates = dataparms{1};
    dataparms = DataTaking(backendreadoutparms,data_time_off);
    double[] offrates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength + shiftlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            if(shiftlength > 0) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 7) {
            // The NOD-state represents our OFF position
            HIFIConfigureLoadChopIntegration(data_time_off,n_per_off,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i1 = 1 .. n_load_off) {
                HIFILoadChopOffIntegration(data_time_off,n_per_off,band,lo_freq,offrates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureLoadChopIntegration(data_time_off,n_per_off,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFILoadChopOffIntegration(data_time_off,n_per_off,band,lo_freq,offrates);
            // Second phase on OFF
            // occurs for even cycle numbers
            runintostate = false;
            if(state[2] % 2 == 0) {
                if(end_load_off) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 3) {
            // The POINT-state represents out source position
            // ON integration
            HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i2 = 1 .. n_load_on) {
                HIFILoadChopOnIntegration(data_time,n_per_on,band,lo_freq,onrates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureLoadChopIntegration(data_time,n_per_on,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFILoadChopOnIntegration(data_time,n_per_on,band,lo_freq,onrates);
            // First phase in source
            // occurs for odd cycle numbers
            runintostate = false;
            if(state[2] % 2 == 1) {
                if(end_load_on) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
        }
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                // (Does not occur if end_load is set)
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

// Get frequency resolution needed to measure standing wave pattern
// in load-chop measurements
double procedure GetLoadChopSWResolution {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] dead = CalibrationReader("lchopswresolution",["resolution"],band,lo_freq);

    return dead[0];
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Not really used anymore
// Initialisation for stability test,
// Rotate chopper to perform backend attenuation setting on hottest spot
block Stability_init_fm HIFI 3427 {
    string band = "1a"; // HIFI band
}{
    Start_block();
    Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_hot_ang");
    //Look at HBB
}

//////////////////////////////////////////////////////////////////////
// Generic procedure to call a Configure_spectroscopy command
// for fast-chop observations
{int,int} procedure FastConfigureSpectroscopy {
    /* Integration time */
    int data_time = 10 in [4,128]; // data dump interval
    int n_int = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used,channel windows} 
}{
    // Get timing parameters
    bool wbs_used = backendreadoutparms{2}{0} || backendreadoutparms{3}{0};
    {int,int,int,int,int,int,int,int,int,int,int,int,int} timing = FastConfigureSpectroscopyParams(data_time,n_int,n_data,band,lo_freq,wbs_used);
    int n_wbs_start = timing{0};
    int r_hrs = timing{1};
    int n_wbs_integr = timing{2};
    int n_hrs_integr = timing{3};
    int del_hrs = timing{4};
    int del_wbs = timing{5};
    int t_acc_wbs = timing{6};
    int t_acc_hrs = timing{7};
    int n_wbs1 = timing{8};
    int n_hrs_trans = timing{9};
    {int,int,int,int,int[],int[],string} backendconfigure = ConfigSpectroscopyBackends(data_time / 2,backendreadoutparms);
    int wbs_rshift = backendconfigure{0};
    int hrs_rshift = backendconfigure{1};
    int hrsh_sel = backendconfigure{2};
    int hrsv_sel = backendconfigure{3};
    int[] wbsh_par = backendconfigure{4};
    int[] wbsv_par = backendconfigure{5};
    string packing = backendconfigure{6};
    // Now call the command
    Hifi_HIFI_config_spectroscopy($BBID,n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,wbsh_par[0],wbsh_par[1],wbsh_par[2],wbsh_par[3],wbsh_par[4],wbsh_par[5],wbsh_par[6],wbsh_par[7],wbsv_par[0],wbsv_par[1],wbsv_par[2],wbsv_par[3],wbsv_par[4],wbsv_par[5],wbsv_par[6],wbsv_par[7],hrs_rshift,wbs_rshift,hrsh_sel,hrsv_sel,packing);
    //
    // Return dead times and comand parameters

    return {n_wbs1,n_hrs_trans};
}

////////////////////////////////////////////////////////
// Testmodes expected to end as manual procedures
// (i.e. no MTL commands) for MOC
// DT - 27-02-07
////////////////////////////////////////////////////////
//Warm-up of 3b band
mode HifiManCmd_LO_Warmup_3b {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    mois_comment("Procedure Switch-on LO band 3b with safe settings");
    StartMode_block_ops();
    //
    mois_step("Switch-on LOU 3b with safe settings");
    LCU_switchon_proc_spur("3b");
    mois_step("Apply higher Vd2");
    LCU_switchon_proc_spur("3b");
    //
    StopMode_block_ops();
    // -> to issue last obsd/bbid
}

//Generic procedure to launch engineering scan applied to chopper rotation, procedure
procedure Engineering_scan_for_closed_loop_scan {
    double targetAngle = 0.0; //Target chopper voltage
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50]; // HIF_N_samples_1
    int samplesAfter = 1000 in [0,1000]; // HIF_N_samples_2
}{
    //
    HIFI_Chopper_scan_fast_proc_fm(milliSecSample,targetAngle,samplesBefore,samplesAfter);
    //
    // delay calculation
    int nb_HK = 1;
    //For this TC, the 2 last HK fields are blanked out
    int millisecondsUsed = 1000 + 10 + milliSecSample * nb_HK * (samplesBefore + samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //
}

//  LCU1a tune: bit flip test, procedure
//  ALL DELAYS DECREASED TO 1 SEC.
procedure LCU1a_bit_flip_proc_fm {
    string band = "1a"; // HIFI band
    double lo_freq = 500.0 in [488.0,552.0]; //LO frequency
    double drain_2_factor = 100.0; //Percentage factor of the targetted drain voltage
    int n = 100; //number of loops
}{
    error("This module is obsolete: use LCU_bit_flip_proc_fm  instead");
}

// Change LO frequency by a small step
//
// Externally it has to be guaranteed that this never uses a step larger
// than one index in the LO table
procedure HIFIChangeFreq {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency ion MHz
}{
    ConfigureFPU(band,lo_freq,false);
    HIFITuneFreqNoretune(band,lo_freq);
}

{int,double,double,double,double,double} obs HifiMappingModeDBSCross {
    string modeName = "cross";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Mapping - DBS Cross Map slowChop",{data_time,0,0,n_switch_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = DBSRaster_pre_timing(2,npoints,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,double[],double[],int[],double,double,int,int,int,int,int,int} tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = custom_map_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSCross_post_timing(pre_timing,telescopetimes,npoints,n_switch_on,n_cycles,load_interval,false);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",post_timing{1},n_cycles);
    telescopetimes = custom_map_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int scansize = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        DBSRaster_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,true);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = DBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,2,npoints,n_cycles,n_seq * imax(n_load,1),tact);
    // Correct for double counting of central point
    // The central point noise is returned only
    double multiplier = sqrt(0.5);
    noisevalues{0} = noisevalues{0} * multiplier;
    noisevalues{1} = noisevalues{1} * multiplier;
    noisevalues{2} = noisevalues{2} * multiplier;
    noisevalues{3} = noisevalues{3} * multiplier;
    noisevalues{4} = noisevalues{4} / multiplier;
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

{string,double,double}[] procedure HifiSScanModeLoadChopSequencerInit {
    string modeName = "load-freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half load-sky-sky-load cycles per frequency and pointing
    int n_switch_off = 1 in [1,900]; // number of half load-sky-sky-load cycles on OFF
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hr1{0},hr1{1},hr1{3}},{hr2{0},hr2{1},hr2{3}},wb1,wb2};
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    // Now general part of LoadChop modes
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {double,double,double,double} phaselengths = LoadChopPhaseLengths(band,lo_freq,effResolution,narrowReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // How much time for single ON phase
    int n_switch_on_guess = imax(iceil(2.0 * phaselengths{0} / ((double(n_freq_point_guess) + sqrt(double(n_freq_point_guess))) * 2.0 * double(data_time_guess))),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) * sqrt(double(n_freq_point_guess)) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)},{"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)}];

    return retvalues;
}

//  LCU4a configuration into SAFE mode, procedure
procedure LCU4a_config_safe_proc_fm {
    string band = "4a"; // HIFI band
    double lo_freq = 1000.0 in [967.0,1042.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

//// END OF OBSOLETE MODULES ////////////////////
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CUS for (some of the) stability tests.
//
// DT - 18 May 2004: first draft
// DT - 19 Aug.2004: - Split tests into various pairs of loads
//		     instead of doing all in a single testmode
//		     - Allow short (1 spec/phase) for non-modulated
//		     integrations and and long (3 spec/phase)
//		     for differential integrations
//		     - Allow non-modulated integration
//	19 Sep 2004: - Updated for QM
//	20 Jul 2005: - Updated for FM. Added new BBID to distinguish
//		       between tests without IF/IF1/IF2, etc..
//
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!
// Modes
//!!!!!!!!!!!!!!!!!!!!!!!!!!
//modes: see fm_testmodes.cus
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Associated high level procedures
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Very fast sampling stability measurement combined with int-load-chop
// Uses only the HRS in wb mode
procedure Stability_chopped_fasthrs_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 522.0; // LO frequency
    int phaselength = 10; // Chop phase length
    int nchop = 10; // Number of phases
    double readout = 0.333; // HRS readout length
    double[] hrs_subband = [5.0,5.0,5.0,5.0]; //Positions in IF of HRS sub-bands
}{
    // Configuration and tuning
    //Configure HRS: regardless of selected bands
    HRS_config_resol_block_fm(band,["wb1","wb1"]);
    HRS_config_att_lo_w_lo_input_block_fm(band,["wb1","wb1"],hrs_subband);
    //Tune backend on cold load
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_cold_ang");
    //Look at CBB
    HRS_tune_block_fm(band);
    // Clean  HK treatment for controlled data rates
    HIFISetHK("fast",false);
    {string,int,double,double,double,double} hkparms = PeriodicHKParms("fast");
    // HK data: stdrate=7744+864+2*272, IF packets=2*(592+272)
    int allhkbits = 1782;
    double hkrate = hkparms{3} + double(allhkbits) / readout;
    // Science data: 2*(2*258*24+1376+3*272)
    int allbits = 29152;
    double sciencerate = double(allbits) / readout;
    // set data rates
    ess_hk_data_rate(hkparms{5} / 1024.0);
    non_ess_hk_data_rate(hkrate / 1024.0);
    data_rate(sciencerate / 1024.0);
    // Run the actual chopped fast-HRS interation
    Stability_chopped_fasthrs_block(band,lo_freq,phaselength,nchop,readout);
    // reset data rates
    non_ess_hk_data_rate(hkparms{3} / 1024.0);
    data_rate(0.0);
}

// WBS attenuator tuning, block
// Both polarizations are treated
block WBS_tune_block_aot HIFI 6603 {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band;
}{
    // Get tuning goal
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["tune_target"],band,0.0);
    int tune_target = iround(result_d[0]{0});
    // Perform tuning
    Tune_WBS_aot(band,tune_target);
}

//Diplexer FSW investigation: phase-block
procedure Dip_FSW_A_phase {
    string band = "3a" in ["3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI band
    bool retune = true; //whether the diplexer is adjusted between frequencies or not
    double lo_freq1 = 810.0;
    double lo_freq_ref = 810.0;
    int[] res = [4,1];
    string backend = "both";
    string polarization = "H" in ["H","V"]; //The polarization on which the test is done
    bool modulate = true; //whether we change FSW register and DPACT
}{
    //Integrate at FSW1
    if(modulate) {
        Activate_FSW_register_block_fm("FSW1");
        if(retune) {
            Set_Single_Diplexer_current_block_fm(band,lo_freq1,polarization);
        } else {
            Set_Single_Diplexer_current_block_fm(band,lo_freq_ref,polarization);
        }
    } else {
        //Hifi_HIFI_noop();
    }
    Spectro_total_power_AOTLike_block_fm(band,res,backend);
    //Add 2sec for investigation of SPR-2404
    delay(2);
}

//HIFI-COP-2.3-CPR-Scan1
procedure Chopper_calibration_COP_proc_ops {
    int band = 1 in [1,7]; // HIFI mixer band
    bool sky = true; //whether or not we scan over M3 area
    int integ_time = 4; //Integration time PER PHASE for the slowchop measurement  
    bool shutter_used = false;
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int freq_index = 1 in [1,3]; //Frequency index: 2 is forbidden if sky=true
}{
    //
    //Read band+freq to perform
    string tab = "configchoppercalib_freq.config";
    int total = table_size(tab);
    double[] freq = [];
    string[] subband = [];
    //We know that mixer bands have at most 3 freq. points
    int i = 3 * (band - 1) + freq_index;
    //If sky path scanned, index 2 is forbidden
    if(sky && freq_index == 2) {
        error("You cannot select frequency index 2 is option sky is selected");
    } else {
        //
        freq[i] = dlookup(tab,"" + i,"frequency");
        subband[i] = slookup(tab,"" + i,"subband");
        //Check whether this combination of band+freq is allowed in the current CUS
        Check_Band_vs_Freq_proc_fm(subband[i],freq[i]);
        //
        //Warm-up time for LO switch-on or frequency change
        LCU_switchon_proc_fm(subband[i]);
        //Wait an extra delay of 1 min for short term stabilization
        delay(60);
        //
        Init_MSA_HBB_fm(subband[i],"CLOSE",freq[i],"ON");
        LO_tuning_block_fm(subband[i],freq[i]);
        Chopper_calibration_proc_fm(band,integ_time,shutter_used,sky,hrs_mode);
        message("band " + subband[i] + ", LO freq " + freq[i]);
    }
    // 
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CUS scripts for spectroscopy operations
// Dedicated FT for spectroscopy are in fm_FT_Spectro.cus
//
// DT - 17-Feb-06
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//The modes
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//modes: see fm_testmodes.cus
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//The procedures
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Spectrometer configuration for total power, procedure
int[] procedure Configure_Spectrometer_proc_fm {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,wb5,wb6,wb7,wb8
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Compute data_time and n_switch use the wrapper
    int[] res = ConfigSlowChop(integ_time,"tp",band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_switch = res[1];
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS. 
    // The deadtimes output is not used at ILT level.
    {double,double} dtimes = ConfigSpectroscopySlowChop_IST(data_time,n_switch,"tp",band,0.0,backendreadoutparms,true);
    //

    return res;
}

// Procedure to perform the HRS tuning including the counting
// of the science data, must be called within a building block
procedure Tune_HRS_aot {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //Get delay
    {double,string}[] result_d = ConfigurationReader("name_delays",["hrs_tune_delay"],band,0.0);
    int hrs_tune_delay = iround(result_d[0]{0});
    // data frame transmission time (always 2 spectra)
    int data_time = hrs_tune_delay / 2;
    int rest_delay = hrs_tune_delay - 2 * data_time;
    hrs_tune_delay = hrs_tune_delay - rest_delay;
    // Compute data rates
    // The HIFI command reads out both full WBS
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} fullreadoutparms = FrequencyCalibrationParms(false,false,true,true);
    {int,double[]} fdataparms = AllDataRates(fullreadoutparms,data_time,false);
    // set data rates (IF power packets are ignored here)
    data_rate(fdataparms{1}[0] / 1024.0);
    //Now tune attenuators: it sets the HRS to ultra_wide
    Hifi_HIFI_Tune_HRS($BBID);
    delay(hrs_tune_delay);
    //
    // reset data rates
    data_rate(0.0);
    delay(rest_delay);
}

//////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the observing mode
//
// The sum of drift noise and radiometric noise is computed.
{double,double,double,double,double} procedure DBS_noisecomputer {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuum = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF pointing cycles
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double} tact = {10.0,4.9,0.05}; // Field of actual dead and integration times
}{
    double tdead = tact{0};
    // Average total dead time in one scan
    double inttimeperphase = tact{1};
    // Actual integration time
    double deadtimeperphase = tact{2};
    // Dead time per switch phase
    // Get parameters which are needed
    double tsys = InterpolateTsys(band,lo_freq);
    double eta_mb = InterpolateCoupling(band,lo_freq);
    double[] gssb = InterpolateGssb(band,lo_freq);
    // Get the drift parameters to compute the drift noise
    if(continuum) {
        double[] allanparms = InterpolateTpAllan(band,lo_freq,oneGHzReference);
    } else {
        allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    }
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double allan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // Differential Allan variance
    if(continuum) {
        allanparms = InterpolateTpChopAllan(band,lo_freq,oneGHzReference);
    } else {
        allanparms = InterpolateSpecChopAllan(band,lo_freq,oneGHzReference);
    }
    // rescale to frequency resolution
    double dalpha = allanparms[1];
    binningexp = 1.0 / allanparms[2];
    double dallan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double dallan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // Compute the relative noise for the detailed timing
    double deadtimeperswitch = deadtimeperphase;
    double inttime = (tscan - tdead) / 2.0;
    // Get actual noise
    // This is returned twice: for both limiting resolutions
    double systemnoise_lores = DoubleDifferenceNoise(inttimeperphase / allan_time_lores,[1.0,1.0,inttime / allan_time_lores,inttime / allan_time_lores,deadtimeperswitch / allan_time_lores,tdead / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    double systemnoise_hires = DoubleDifferenceNoise(inttimeperphase / allan_time_hires,[1.0,1.0,inttime / allan_time_hires,inttime / allan_time_hires,deadtimeperswitch / allan_time_hires,tdead / allan_time_hires,alpha,dallan_time_hires / allan_time_hires,dalpha]);
    double noiseratio = DoubleDifferenceNoiseRatio(inttimeperphase / allan_time_lores,[1.0,1.0,inttime / allan_time_lores,inttime / allan_time_lores,deadtimeperswitch / allan_time_lores,tdead / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    // Compute total double sideband noise 
    // Correct for signal in difference phase
    double dsbnoise_lores = tsys * sqrt(systemnoise_lores / (eff_resolution{1} * 4000000.0 * double(n_cycles) * tscan));
    double dsbnoise_hires = tsys * sqrt(systemnoise_hires / (eff_resolution{0} * 4000000.0 * double(n_cycles) * tscan));
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Get single sideband noise equivalent
    double usbnoise_lores = dsbnoise_lores / gssb[0];
    double usbnoise_hires = dsbnoise_hires / gssb[0];
    double lsbnoise_lores = dsbnoise_lores / gssb[1];
    double lsbnoise_hires = dsbnoise_hires / gssb[1];
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiseratio};
}

//Recalculation of checksum
//To be run only after upload of both 
mode HifiManCmd_recalc_LCU_checksum_flight {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string section = "P" in ["P","R"];
}{
    mois_comment("This procedure cannot be performed before completion of both HIF_CUPM and HIF_NUT");
    mois_step("Recompute checksum and verify against expected value");
    StartMode_block_ops();
    LcuChecksumRecalc_ops(section);
    StopMode_block_ops();
}

//Set LOU to nominal, block
//Set LOU in nominal mode with no channel selected
block Set_LO_Nominal_block_aot HIFI 6626 {
}{
    {double,string}[] result = ConfigurationReader("name_delays",["set_to_nominal_delay"],"0",0.0);
    int set_to_nominal_delay = iround(result[0]{0});
    //
    Hifi_HIFI_HL_Normal($BBID);
    delay(set_to_nominal_delay);
    //
}

//General script to clear error flags and set to nominal, block
block LCU_enable_all_bands_block_fm HIFI 3769 {
}{
    //
    //switch to standby
    {double,string}[] result = ConfigurationReader("name_delays",["stdby_delay"],"0",0.0);
    int stdby_delay = iround(result[0]{0});
    mois_comment("Set LOU to standby");
    Hifi_HIFI_HL_Standby($BBID);
    delay(stdby_delay);
    //Enable all bands
    mois_comment("Enable all bands");
    mois_spacon("In the next TC, parameters HP444194 and HP443194 should be treated as FP");
    Hifi_HIFI_Conf_LCU_internal($BBID,16383,"RESET","RESET",256);
    //sets bandmask to 3FFF: all bands
    //LSU_delta_f: 256 = 88mV
    //
}

// Procedure used by the mapping sequencer to compute the
// OFF integration time
int procedure SpotOTFOffTime {
    /* Basic setup */
    string band = "4a";
    double fe_lof_0 = 978.2;
    /* Map parameters */
    double flyX = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    /* Other sequence parameters */
    int n_int_on = 1;
    int n_linesperscan = 1;
}{
    // start Volkers list
    double lo_freq = 978200.0;
    // Lower LO frequency limit in MHz
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    // general definitions
    double factorMHzPerGHz = 1000.0;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    // start translation
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    // Map size
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,lo_freq);
        stepsize = s[0];
    }
    npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
    // derive OFF integration time
    double n_pointsperscan = double(n_linesperscan * npoints);
    int n_switch_off = iceil(double(n_int_on) * 0.67 * sqrt(n_pointsperscan));

    return n_switch_off;
}

/////////////////////////////////////////////////////////////////
// New routine to select the reference frequency as the median
// of the three relevant points with respect to Tsys
double procedure ComputeReferenceFreq {
    string band = "4a"; // HIFI band
    double lo_freq1 = 978200.0 in [480000.0,1950000.0]; // LO frequency
    double lo_freq2 = 979600.0 in [480000.0,1950000.0]; // LO frequency
}{
    // standard guess - center of the interval
    double reffreq = 0.5 * (lo_freq1 + lo_freq2);
    double t1 = InterpolateTsys(band,reffreq);
    double t2 = InterpolateTsys(band,lo_freq1);
    double t3 = InterpolateTsys(band,lo_freq2);
    // first check for exclusion of really bad values
    double excludelimit = 1.414;
    // sqrt(2) factor
    double bestt = min(min(t1,t2),t3);
    excludelimit = excludelimit * bestt;
    bool twoexcluded = false;
    // go through the three possible combinations
    if(t1 > excludelimit && t2 > excludelimit) {
        reffreq = lo_freq2;
        twoexcluded = true;
    }
    if(t1 > excludelimit && t3 > excludelimit) {
        reffreq = lo_freq1;
        twoexcluded = true;
    }
    if(t2 > excludelimit && t3 > excludelimit) {
        twoexcluded = true;
    }
    // Treatment for at least two valid points - use median
    if(!twoexcluded) {
        // go through the possible combinations
        if(t1 > t2 && t2 >= t3 || t1 < t2 && t2 <= t3) {
            reffreq = lo_freq1;
        }
        if(t1 > t3 && t3 > t2 || t1 < t3 && t3 < t2) {
            reffreq = lo_freq2;
        }
    }

    return reffreq;
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure DBSRaster_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int nlines = 20; // Number of lines in the map
    int npoints = 20; // Number of points in the map
    int n_cycles = 1; // Number of nodding cycles
    int n_chop = 1; // number of chop cycles
    {double,double,double} tact = {10.0,4.9,0.05}; // Field of actual dead and integration times
}{
    double inttimeperphase = tact{1};
    // Actual integration time in ON phase
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    double idealnoise = idealvalues{1} * idealvalues{1};
    double obsnoise = noisevalues{0} * noisevalues{0};
    // rescale for map coverage
    idealnoise = idealnoise * double(npoints * nlines);
    double efficiency = idealnoise / obsnoise;
    // Compute the actual integration time
    double posinttime = double(npoints * nlines * n_cycles * 2 * n_chop) * inttimeperphase;
    // Check total integration time
    double timeefficiency = 2.0 * posinttime / double(totaltime);
    // Noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // Non-standard messages
    message("</p><p>");
    message("The observed map consists of " + nlines + " lines with " + npoints + " points in each line.<br>");
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posinttime,timeefficiency,efficiency,relnoise,false);
}

//Single parameter change in FPU setting, block
//Testmode dedicated to tests on FPU-C sim. Parameters
//are changed 1 by 1 by operator and directly measured on simulator
block Single_FPU_Param_Change_block_fm HIFI 3648 {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 522.0; //LO frequency  
    string param_code = "DIPL" in ["DIPL","MAGN","MBIAS","CHOPV","CALIBC","FIF1V","FIF1C","FIF2V","FIF2C","SIF1V","SIF1C","SIF2V","SIF2C","SIF3V","SIF3C"]; //The parameter to scan: DIPL, MAG, MBIAS, FIF/SIF1V/C, FIF/SIF2V/C, SIF3V/C
    double param_value = 0.0; //Value for parameter to be set
    string context = "warm" in ["warm","cold"]; //Test context: warm or cold
}{
    Start_block();
    //Read out all parameters as in config files: does as init_MSA.
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    if(context == "warm") {
        result_d = ConfigurationReaderWarm("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    }
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    if(context == "warm") {
        result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    }
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    string chop_loop = "CLOSE";
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    if(context == "warm") {
        result_d = ConfigurationReaderWarm("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    }
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    if(context == "warm") {
        result_d = ConfigurationReaderWarm("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    }
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        if(context == "warm") {
            result_d = ConfigurationReaderWarm("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        }
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        if(context == "warm") {
            result_d = ConfigurationReaderWarm("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        }
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    //Chopper on hot load
    result_d = ConfigurationReader("name_confilfpu",["chop_hot"],band,lo_freq);
    if(context == "warm") {
        result_d = ConfigurationReaderWarm("name_confilfpu",["chop_hot"],band,lo_freq);
    }
    double chopper = result_d[0]{0};
    //
    //Update parameter changed by user
    if(param_code == "DIPL") {
        diplex_H = param_value;
        diplex_V = param_value;
    }
    if(param_code == "MAGN") {
        magnetcurrent_H = param_value;
        magnetcurrent_V = param_value;
    }
    if(param_code == "MBIAS") {
        bias_H = param_value;
        bias_V = param_value;
    }
    if(param_code == "CHOPV") {
        chopper = param_value;
    }
    if(param_code == "CALIBC") {
        calibcurrent = param_value;
    }
    if(param_code == "FIF1V") {
        volt_H_FIF_1 = param_value;
        volt_V_FIF_1 = param_value;
    }
    if(param_code == "FIF1C") {
        curr_H_FIF_1 = param_value;
        curr_V_FIF_1 = param_value;
    }
    if(param_code == "FIF2V") {
        volt_H_FIF_2 = param_value;
        volt_V_FIF_2 = param_value;
    }
    if(param_code == "FIF2C") {
        curr_H_FIF_2 = param_value;
        curr_V_FIF_2 = param_value;
    }
    if(param_code == "SIF1V") {
        volt_H_SIF_1 = param_value;
        volt_V_SIF_1 = param_value;
    }
    if(param_code == "SIF1C") {
        curr_H_SIF_1 = param_value;
        curr_V_SIF_1 = param_value;
    }
    if(param_code == "SIF2V") {
        volt_H_SIF_2 = param_value;
        volt_V_SIF_2 = param_value;
    }
    if(param_code == "SIF2C") {
        curr_H_SIF_2 = param_value;
        curr_V_SIF_2 = param_value;
    }
    if(param_code == "SIF3V") {
        volt_H_SIF_3 = param_value;
        volt_V_SIF_3 = param_value;
    }
    if(param_code == "SIF3C") {
        curr_H_SIF_3 = param_value;
        curr_V_SIF_3 = param_value;
    }
    //
    chopper = Check_Chopper_Prime_Redundant(chopper);
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
}

//Set LCU1b back to standby status, procedure
procedure LCU1b_standby_proc_fm {
    string band = "1b"; // HIFI band
    double lo_freq = 600.0 in [566.0,633.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

// Integrate with only backends, block
// We take 1 spectrum per phase.
block Stability_backend_fm HIFI 3428 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integrations
    int integ_time = 4; //Total integration time in sec. to be set at end of test 
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    Start_block();
    //The system as is should be ready
    //No use of FPU capabilities.
    //
    //Do a long integration: 4 sec. is OK
    //We implement a special spectroscopy configuration with fixed values
    Total_power_spectro_for_Stability_proc_fm(band,n,integ_time,backend,hrs_mode);
}

//HIFI LO tuning only for M3 investigation in 3b, block
//Target current is read from look-up table
block LO_tuning_w_M3_block_fm HIFI 3818 {
    string band = "3b" in ["3b","3b"]; // HIFI band
    double lo_freq = 930.0; //LO frequency
    double m3 = -0.5; //M1 multiplier voltage
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    string mixer_polarization = result[0]{1};
    //
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = m3;
    //result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    //multiplier settings which are not passed as input must be
    //taken from safe table
    if(band == "3b") {
        double[] cresult = CalibrationReader("name_lcu_safe_values",["m1_v","m2_v","m3_v"],band,lo_freq);
        m1_v = cresult[0];
        m2_v = cresult[1];
    }
    //
    cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double middle_d2 = result[0]{0};
    double drain2_v_start = drain2_bluemax;
    //min(middle_d2*(1.+tune_range/2.),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * middle_d2;
    //drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    if(band == "3b") {
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum);
        //Send command: specific to M3 in 3b
        delay(config_lo_delay);
        //
        //Additional read of TM pages
        LCU_Read_TM_pages_proc_fm();
    } else {
        //
        //General command
        HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    }
    //
    //delay(5);	//to settle at this value
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//////////////////////////////////////
// Procedures
//////////////////////////////////////
// HRS partial configuration, procedure
// Configures the resolution mode
procedure HRS_config_resol_proc_ops {
    string band = "0"; // HIFI band
    string[] hrs_mode = ["wb","wb"]; //HRS resolution code
}{
    ////////////////////////////////////////////////////////////////////
    //Now Configure blocks
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_block_1","hrh_block_2","hrh_block_3","hrh_block_4","hrh_block_5","hrh_block_6","hrh_block_7","hrh_block_8"],band,0.0);
    string hrh_block_1 = result[0]{1};
    string hrh_block_2 = result[1]{1};
    string hrh_block_3 = result[2]{1};
    string hrh_block_4 = result[3]{1};
    string hrh_block_5 = result[4]{1};
    string hrh_block_6 = result[5]{1};
    string hrh_block_7 = result[6]{1};
    string hrh_block_8 = result[7]{1};
    string resol_mode_h = hrh_block_3;
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrh_block_1,hrh_block_2,hrh_block_3,hrh_block_4,hrh_block_5,hrh_block_6,hrh_block_7,hrh_block_8);
    //delay(hrs_config_delay);
    //
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_block_1","hrv_block_2","hrv_block_3","hrv_block_4","hrv_block_5","hrv_block_6","hrv_block_7","hrv_block_8"],band,0.0);
    string hrv_block_1 = result[0]{1};
    string hrv_block_2 = result[1]{1};
    string hrv_block_3 = result[2]{1};
    string hrv_block_4 = result[3]{1};
    string hrv_block_5 = result[4]{1};
    string hrv_block_6 = result[5]{1};
    string hrv_block_7 = result[6]{1};
    string hrv_block_8 = result[7]{1};
    string resol_mode_v = hrv_block_3;
    //
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrv_block_1,hrv_block_2,hrv_block_3,hrv_block_4,hrv_block_5,hrv_block_6,hrv_block_7,hrv_block_8);
    //
    //Wait delay to allow all setting to be configured
    delay(hrs_config_delay);
    //Check HK - depends on the configured mode
    if(hrs_mode[0] == "hr") {
        resol_mode_h = "corr_high";
    }
    if(hrs_mode[1] == "hr") {
        resol_mode_v = "corr_high";
    }
    if(hrs_mode[0] == "mr") {
        resol_mode_h = "corr_nominal";
    }
    if(hrs_mode[1] == "mr") {
        resol_mode_v = "corr_nominal";
    }
    //removed as this only appears when taking science data
    //mois_tmcheck("Check that parameters HRH_config and HRV_config are respectively " + resol_mode_h + " and " + resol_mode_v);
}

////////////////////////////////////
// Test mode - Load chop mode without baseline calibration
// 
{int,double,double,double,double,double} obs HifiPointProcLoadChopNoRef_FCal {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_cycles = 2 in [1,3600]; // number of half load-sky-sky-load cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Engineering - Load Chop noRef newComb",{data_time,0,0,0,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,bool,int,int} pre_timing_f = LoadChopNoRef_FCal_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_cycles,load_interval,docommands);
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,double,double,int} tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,pre_timing_f);
    // Dummy call to spacecraft command
    int[] telescopetimes = basic_fine_pointing(false,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,bool,int,int},double,double} post_timing_f = SingleChopNoRef_post_timing(pre_timing_f,telescopetimes);
    // Now the actual observation starts
    // Prepare telescope command
    tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,post_timing_f{1});
    // Call telescope command 
    telescopetimes = basic_fine_pointing(true,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
    // Consistency check
    int totaltime = post_timing_f{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    //////////////////////////////////////////////////////////////////////
    // standard parameters for fine pointing
    int loadlength = post_timing_f{1}{2};
    int n_per_on = post_timing_f{1}{4};
    int n_load_on = post_timing_f{1}{5};
    bool end_load_on = post_timing_f{1}{6};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    //////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        LoadChopNoRef_FCal_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_per_on,n_load_on,end_load_on,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // There are no telescope dead times involved in this mode
    {double,double,double} tact = SingleChop_deadtimes("lchop",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_per_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = PositionSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_per_on * (n_load_on + 1),tscan,tdead);
    // Evaluate performance
    SingleChopNoRef_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_per_on * (n_load_on + 1),false,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// WBS linearity test, loop on individual attenuators, block
block FT_WBS_linearity_indiv HIFI 3710 {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //
    //Set zero and comb off
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_OFF");
    delay(2);
    //
    //Initial configuration: overall attenuators set to max., individual attenuators to 0
    //H-Polarization
    //
    {double,string}[] result = ConfigurationReader("name_configwbs",["hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result[0]{0});
    string hwh_latchup_s = result[1]{1};
    int hwh_att_band4 = 8;
    int hwh_att_band3 = 8;
    int hwh_att_band2 = 8;
    int hwh_att_band1 = 8;
    int hwh_att_in = 0;
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result[0]{0});
    string hwv_latchup_s = result[1]{1};
    int hwv_att_band4 = 8;
    int hwv_att_band3 = 8;
    int hwv_att_band2 = 8;
    int hwv_att_band1 = 8;
    int hwv_att_in = 0;
    //
    //Loop on overall attenuators
    for(int i = 0 .. 7) {
        // Change the value of the individual attenuators
        //===============================================
        hwh_att_band4 = hwh_att_band4 - 1;
        hwh_att_band3 = hwh_att_band3 - 1;
        hwh_att_band2 = hwh_att_band2 - 1;
        hwh_att_band1 = hwh_att_band1 - 1;
        // Set WBS
        //========
        //0dB attenuation on main attenuators
        hwh_att_in = 0;
        hwv_att_in = 0;
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        hwv_att_band4 = hwv_att_band4 - 1;
        hwv_att_band3 = hwv_att_band3 - 1;
        hwv_att_band2 = hwv_att_band2 - 1;
        hwv_att_band1 = hwv_att_band1 - 1;
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
        //
        //1dB attenuation on main attenuator
        hwh_att_in = 1;
        hwv_att_in = 1;
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
    }
    //Set att. to max.
    WBS_config_proc_max_att_w_laser_fm(band,laser_H,laser_V);
    //
}

//Systematic deflux at beginning of each band switch
procedure Deflux_SingleBand_proc_aot {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; // LO frequency in GHz
}{
    //Do deflux block only for bands 1 to 4
    if(band == "1a" || band == "1b" || band == "2a" || band == "2b" || band == "3a" || band == "3b" || band == "4a" || band == "4b") {
        //First magnet tuning
        Magnet_tuning_block_aot(band,lo_freq,"HRS");
        //Deflux heaters
        Heater_block_aot(band);
        //Second magnet tuning
        Magnet_tuning_block_aot(band,lo_freq,"HRS");
    }
}

////////////////////////////////////
// Auxiliary function to compute the noise of an ideal instrument with
// 100% observing efficiency for comparison
{int,double,double,double,double,double} procedure IdealInstrument {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    int totaltime = 8; // Total integration time
}{
    // Get parameters which are needed
    double tsys = InterpolateTsys(band,lo_freq);
    double eta_mb = InterpolateCoupling(band,lo_freq);
    double[] gssb = InterpolateGssb(band,lo_freq);
    double phasetime = double(totaltime);
    double noiseratio = 0.0;
    // Compute total double sideband noise 
    double dsbnoise_lores = tsys * sqrt(1.0 / (eff_resolution{1} * 1000000.0 * phasetime));
    double dsbnoise_hires = tsys * sqrt(1.0 / (eff_resolution{0} * 1000000.0 * phasetime));
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Get single sideband noise equivalent
    double usbnoise_lores = dsbnoise_lores / gssb[0];
    double usbnoise_hires = dsbnoise_hires / gssb[0];
    double lsbnoise_lores = dsbnoise_lores / gssb[1];
    double lsbnoise_hires = dsbnoise_hires / gssb[1];
    // return total time with initial slew
    int returntime = totaltime;
    // Originally I had added 180s from telescope
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {returntime,usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiseratio};
}

//Reduced version: IVC
//HIFI-COP-7.2-FPU_FT
obs HifiEng_FPU_FT_IVC_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b","8"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(FPU_FT_IVC_COP_proc_ops(band,prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            FPU_FT_IVC_COP_proc_ops(band,prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

/////////////////////////////////////////////////////////////////
// Procedure to derive the backend settings for the peakup
{{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} procedure PeakupBackendSettings {
    string backend = "WBS" in ["WBS","HRS"]; // backend to use - resolution
    string polarization = "H" in ["H","V"]; // backend to use - polarization
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int redundancy = 4; // Equivalent frequency scan redundancy
}{
    // First get the backend configuration
    bool isWbs = backend == "WBS";
    bool isH = polarization == "H";
    // Settings for unused spectrometers
    int[][] emptyWbsWindows = [[0,0],[0,0],[0,0],[0,0]];
    {bool,int,double[],bool[]} unusedHrs = {false,1,[-110.0,110.0,0.0,0.0],[false,false,false,false]};
    // Standard configuration of the backends
    if(isWbs) {
        // Get normal WBS windows
        double[] x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,lo_freq);
        int[][] stdWbsWindows = [[iround(x[0]),iround(x[1])],[iround(x[2]),iround(x[3])],[iround(x[4]),iround(x[5])],[iround(x[6]),iround(x[7])]];
        // Assign to polarizations
        if(isH) {
            {bool,int[][]} wbs1 = {true,stdWbsWindows};
            {bool,int[][]} wbs2 = {false,emptyWbsWindows};
            {bool,int,double[],bool[]} hrs1 = unusedHrs;
            {bool,int,double[],bool[]} hrs2 = unusedHrs;
        } else {
            wbs1 = {false,emptyWbsWindows};
            wbs2 = {true,stdWbsWindows};
            hrs1 = unusedHrs;
            hrs2 = unusedHrs;
        }
    } else {
        // Get fixed HRS parameters
        {{bool,int,double[],bool[]},{bool,int,double[],bool[]}} hrsparms = GetSpectralScanHRS(redundancy,band);
        if(isH) {
            hrs1 = hrsparms{0};
            hrs2 = unusedHrs;
            wbs1 = {false,emptyWbsWindows};
            wbs2 = {false,emptyWbsWindows};
        } else {
            hrs1 = unusedHrs;
            hrs2 = hrsparms{1};
            wbs1 = {false,emptyWbsWindows};
            wbs2 = {false,emptyWbsWindows};
        }
    }

    return {hrs1,hrs2,wbs1,wbs2};
}

//TM to control heater values of LOU, block
block HL_heater_test_block_fm HIFI 3915 {
    double hifi_HL_heater = 0.0 in [0.0,6.0]; // HL_heater
}{
    //Start_block();
    Hifi_HIFI_HL_heater($BBID,hifi_HL_heater);
    delay(1);
}

/////////////////////////////////////////////////////////////////
// Spectral scan in frequency switch without OFF calibration
// 
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiSScanProcFSwitchNoRef {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_cycles = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - Frequency Switch noRef",{data_time,0,0,0,0,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = SScanFSwitchNoRef_pre_timing(band,lo_freq,lo_freq_up,redundancy,freq_throw,effResolution,hr1,hr2,wb1,wb2,data_time,n_cycles,n_freq_point,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,double,double,int} tpar = Fine_telescope(naifid,onPosition,band,reffreq,pre_timing{0});
    // Dummy call to spacecraft command
    int[] telescopetimes = basic_fine_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,bool,int,int},double,double} post_timing = SScanChopNoRef_post_timing(pre_timing{0},telescopetimes);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = Fine_telescope(naifid,onPosition,band,reffreq,post_timing{1});
    // Call telescope command
    telescopetimes = basic_fine_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    // normal pre_timing values
    int loadlength = post_timing{1}{2};
    int n_per_on = post_timing{1}{4};
    int n_load_on = post_timing{1}{5};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        SScanFSwitchNoRef_commanding(band,reffreq,freq_throw,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,n_per_on,n_load_on,groupnumber,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SingleChop_deadtimes("fs",band,reffreq,hr1,hr2,wb1,wb2,data_time,n_per_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanChopNoRef_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,n_per_on * imax(n_load_on,1),true,tscan,tdead);
    // Evaluate performance
    SScanChopNoRef_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_per_on * imax(n_load_on,1),groupnumber * n_freq_point,true,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//  LCU configuration into NOMINAL mode, procedure
//  Uses SFT approach with old 5 TM TC call
procedure LCU_config_nominal_w_D2_proc_sft {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    double drain2_v = 1.4; //Drain2 voltage in V
}{
    //Clear potential failure mode
    Set_LO_Nominal_block_fm();
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_confindex = "name_confindex_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command: expect that we have already switched to NOMINAL
    //Contrary to QM, the channel is automatically switched ON
    HIFI_Configure_LCU_block_sft(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,config_lo_delay);
    //
}

/////////////////////////////////////////////////////////////////
// Procedure to simulate a spectral scan frequency change using
// HSPOT parameters needed by the sequencer
// 
procedure SScanRetuning {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double fe_lof_0 = 978.2; //LO frequency in normal modes
    double lo_freq1 = 978.2; //LO frequency in spectral scans
}{
    double lo_freq = 978.2;
    // LO frequency in MHz
    if(lo_freq == lo_freq1) {
        lo_freq = fe_lof_0 * 1000.0;
    } else {
        lo_freq = lo_freq1 * 1000.0;
    }
    HIFIRetuneFreq(band,lo_freq,"");
}

//////////////////////////////////////////////////////////////////////////
// Auxiliary procedure to compute sum of dead times across the map
{int,int} procedure Raster_slewtimes {
    /* Map setup */
    int nlines_tot = 1; // Number of rows in the map
    int npoints = 10; // Number of points per row
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF pointing cycles
    int scansize = 1; // Number of points measured in one scan
    /* Telescope dead times */
    int nodtime = 20; // Slew time to second nod
    int slewtime = 10; // Slew time to next point
    int slewline = 10; // Slew between lines
    int returntime = 2; // Idle time between two phases
}{
    ///////////////////////
    // Long computation for scansize > 1 to obtain all slew durations
    // create field of slews in the maps for simple counting
    if(scansize > 1) {
        // Create array containing all slews
        int[] inslews = [];
        int slewcount = -1;
        for(int icycl = 0 .. n_cycles - 1) {
            for(int iline = 0 .. nlines_tot - 1) {
                for(int ipoints = 0 .. npoints - 1) {
                    slewcount = slewcount + 1;
                    inslews[slewcount] = slewtime;
                }
                inslews[slewcount] = slewline;
            }
            inslews[slewcount] = returntime;
        }
        inslews[slewcount] = 0;
        // Count all slews using the array produced above
        int tinscandead = 0;
        int toutscandead = 0;
        // map point counter
        int slew1 = 0;
        int slew2 = 0;
        bool inmap1 = true;
        // k-2k-2k .. phase indicator
        bool aphase1 = false;
        bool aphase2 = true;
        while(slew1 <= slewcount || slew2 <= slewcount) {
            // A pointing phase
            if(inmap1) {
                slew1 = slew1 + 1;
                if(slew1 % scansize == 0) {
                    aphase1 = !aphase1;
                    if(aphase1) {
                        tinscandead = tinscandead + nodtime;
                        inmap1 = !inmap1;
                    } else {
                        toutscandead = toutscandead + inslews[slew1 - 1];
                    }
                } else {
                    tinscandead = tinscandead + inslews[slew1 - 1];
                }
            } else {
                // B pointing phase
                slew2 = slew2 + 1;
                if(slew2 % scansize == 0) {
                    aphase2 = !aphase2;
                    if(aphase2) {
                        tinscandead = tinscandead + nodtime;
                        inmap1 = !inmap1;
                    } else {
                        toutscandead = toutscandead + inslews[slew2 - 1];
                    }
                } else {
                    tinscandead = tinscandead + inslews[slew2 - 1];
                }
            }
        }
    } else {
        // Single point per nod
        int n_scans = nlines_tot * npoints / scansize;
        tinscandead = n_scans * n_cycles * nodtime;
        toutscandead = nlines_tot * (npoints - 1) * slewtime + (nlines_tot - 1) * slewline + n_scans * (n_cycles - 1) * returntime;
    }

    return {tinscandead,toutscandead};
}

//////////////////////////////////////////////////////////////////////
// Compatibility procedure to provide the same API as used in
// the previous versions
//
// Returns the actual integration time and the dead time per phase
{double,double} procedure ConfigSpectroscopySlowChop_IST {
    /* Integration time */
    int data_time = 4; // Integration time between two data readouts
    int n_data = 2; // Integration time counter
    /* Parameters determining the delays - used in calibration reader */
    string chopmode = "chop" in ["chop","lchop","fs","hot-cold","tp","chopcal"]; // Chop mode determining the modulation dead time
    string band = "1a"; // HIFI band
    double lo_freq = 522000.0; // LO frequency
    /* Backend settings */
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used,channel windows}
    bool docommands = false; // Whether instrument command is issued
}{
    // Get timing parameters
    {int,int,int,int,int,int,int,int,int,int} timing = ConfigureSpectroscopyParams_IST(data_time,n_data,chopmode,band,lo_freq,backendreadoutparms);
    int n_wbs_start = timing{0};
    int r_hrs = timing{1};
    int n_wbs_integr = timing{2};
    int n_hrs_integr = timing{3};
    int del_hrs = timing{4};
    int del_wbs = timing{5};
    int t_acc_wbs = timing{6};
    int t_acc_hrs = timing{7};
    int tdead = timing{8};
    int tint_act = timing{9};
    // Transfer mode
    {int,int,int,int,int[],int[],string} backendconfigure = ConfigSpectroscopyBackends(data_time,backendreadoutparms);
    int wbs_rshift = backendconfigure{0};
    int hrs_rshift = backendconfigure{1};
    int hrsh_sel = backendconfigure{2};
    int hrsv_sel = backendconfigure{3};
    int[] wbsh_par = backendconfigure{4};
    int[] wbsv_par = backendconfigure{5};
    string packing = backendconfigure{6};
    // Now call the command
    if(docommands) {
        Hifi_HIFI_config_spectroscopy($BBID,n_wbs_start,r_hrs,n_wbs_integr,n_hrs_integr,del_hrs,del_wbs,t_acc_wbs,t_acc_hrs,wbsh_par[0],wbsh_par[1],wbsh_par[2],wbsh_par[3],wbsh_par[4],wbsh_par[5],wbsh_par[6],wbsh_par[7],wbsv_par[0],wbsv_par[1],wbsv_par[2],wbsv_par[3],wbsv_par[4],wbsv_par[5],wbsv_par[6],wbsv_par[7],hrs_rshift,wbs_rshift,hrsh_sel,hrsv_sel,packing);
    }
    // Return actual integration time and dead time per readout

    return {double(tint_act) / 1000.0,double(tdead) / 1000.0};
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of OTF observing mode
{int,int,int,int,int,int,int,int} procedure OTFLoadChop_pre_timing {
    int nlines_tot = 1; // Number of rows in the map
    int npoints = 10; // Number of data dumps per row
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    // Is the map size an integer multiple of the scan size?
    CheckReasonableLineNumber(nlines_tot,true);
    if(nlines_tot == 1) {
        int n_scans = 1;
    } else {
        if(nlines_tot % n_linesperscan != 0) {
            SError("Map size is no integer multiple of the scan size.");
        }
        n_scans = nlines_tot / n_linesperscan;
    }
    // Compute parameters for the instrument timing
    int n_pp = 2 * npoints * n_switch_on;
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Compute parameters for the pointing command
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    int off_inttime = 2 * data_time_off * n_switch_off;
    // OFF integration time
    int off_pointing = off_inttime + jitterdead;
    // increase by commanding jitter
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,false);
    }
    initlength = initlength + loadlength;
    // First estimate of the load interval
    int scan_time = n_linesperscan * n_pp * data_time + off_pointing;
    if(scan_time > load_interval) {
        IError("Scan duration too long for required load period. " + "Reduce the map size or increase the step size.");
    }
    int n_loadinterval = imax(load_interval / scan_time,1);
    n_loadinterval = imin(n_loadinterval,32);
    // Make sure that load slews occur at the same position in each coverage
    n_loadinterval = IMultiple(n_loadinterval,n_scans);
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed in the observing mode modules

    return {n_pp,n_scans,off_inttime,off_pointing,loadlength,n_loadinterval,initlength,dangling};
}

//Generic procedure to configure the FPU using the adequate instrument side
procedure HIFI_Configure_FCU_proc_fm {
    int band_nb = 0; // HF_CPR_MXBAND
    int diplex_h_ctrl_mode = 227; // HF_CV1_DPFPP1
    double volt_H_FIF_1 = 0.075; // HF_CH2_FIF1_Drain_V
    double curr_H_FIF_1 = 0.5; // HF_CH2_FIF1_Drain_C
    double volt_H_FIF_2 = 0.075; // HF_CH2_FIF2_Drain_V
    double curr_H_FIF_2 = 0.5; // HF_CH2_FIF2_Drain_C
    double volt_H_SIF_1 = 0.075; // HF_CH2_SIF1_Drain_V
    double curr_H_SIF_1 = 0.5; // HF_CH2_SIF1_Drain_C
    double volt_H_SIF_2 = 0.075; // HF_CH2_SIF2_Drain_V
    double curr_H_SIF_2 = 0.5; // HF_CH2_SIF2_Drain_C
    double volt_H_SIF_3 = 0.075; // HF_CH2_SIF3_Drain_V
    double curr_H_SIF_3 = 0.5; // HF_CH2_SIF3_Drain_C
    int diplex_v_ctrl_mode = 227; // HF_CV1_DPFPP1
    double volt_V_FIF_1 = 0.075; // HF_CV2_FIF1_Drain_V
    double curr_V_FIF_1 = 0.5; // HF_CV2_FIF1_Drain_C
    double volt_V_FIF_2 = 0.075; // HF_CV2_FIF2_Drain_V
    double curr_V_FIF_2 = 0.5; // HF_CV2_FIF2_Drain_C
    double volt_V_SIF_1 = 0.075; // HF_CV2_SIF1_Drain_V
    double curr_V_SIF_1 = 0.5; // HF_CV2_SIF1_Drain_C
    double volt_V_SIF_2 = 0.075; // HF_CV2_SIF2_Drain_V
    double curr_V_SIF_2 = 0.5; // HF_CV2_SIF2_Drain_C
    double volt_V_SIF_3 = 0.075; // HF_CV2_SIF3_Drain_V
    double curr_V_SIF_3 = 0.5; // HF_CV2_SIF3_Drain_C
    string chop_sine_s = "ON" in ["OFF","ON"]; // HF_CPR_CH_SINE_S
    string chop_loop = "CLOSE" in ["CLOSE","OPEN"]; // HF_CPR_CH_LOOP_S
    int chop_G1 = 0; // HF_CPR_CHFPG1
    int chop_G2 = 0; // HF_CPR_CHFPG2
    int chop_Z1 = 0; // HF_CPR_CHFPZ1
    int chop_Z2 = 0; // HF_CPR_CHFPZ2
    int chop_P2 = 0; // HF_CPR_CHFPP2
    double calibcurrent = 0.0; // HF_CPR_Cal_Heater_C
    double bias_H = 0.0; // HF_CH1_MXBIAS_V
    double magnetcurrent_H = 0.0; // HF_CH1_MX_MG_C
    double bias_V = 0.0; // HF_CV1_MXBIAS_V
    double magnetcurrent_V = 0.0; // HF_CV1_MX_MG_C
    double chopper = -4.0 in [-8.88,8.5]; // HF_CPR_Chopper_Rot
    double diplex_H = 0.0; // HF_CH1_DPACT_C
    double diplex_V = 0.0; // HF_CV1_DPACT_C
}{
    //check prime or redundant keyword
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant"],"0",0.0);
    if(result_d[0]{1} == "prime") {
        Hifi_HIFI_P_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    } else {
        Hifi_HIFI_R_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    }
    //
}

// Mode initialisation, block
// Same content as "block HIFIInitObs HIFI 6000"
block StartMode_block_ops HIFI 7922 {
}{
    mois_comment("Assign obsid number to procedure execution");
    mois_spacon("In the following command, the second parameter (OBS_ID) shall be replaced by a Formal Parameter value according to the list provided by the instrument ICC.");
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
}

{int,double,double,double,double,double} obs HifiMappingModeFastDBSRaster {
    string modeName = "raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Mapping - DBS Raster Map fastChop",{data_time,0,n_switch_on,n_int_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = FastDBSRaster_pre_timing(nlines,npoints,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    // Check for NoddingInRaster or NoddingOfRaster
    int scansize = pre_timing{10};
    if(scansize > 1) {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,double,double,int,int,int,int,int} tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        // Dummy call to spacecraft command
        int[] telescopetimes = nodding_of_raster_pointing(false,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double,int,int,int,double,double,int,int,int,int} tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        telescopetimes = nodding_raster_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSRaster_post_timing(pre_timing,telescopetimes,nlines,npoints,n_switch_on,n_cycles,load_interval,true);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    if(scansize > 1) {
        tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        // Call telescope command
        telescopetimes = nodding_of_raster_pointing(true,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        telescopetimes = nodding_raster_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FastDBSRaster_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,false);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastDBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints,n_cycles,n_seq * n_int_on * imax(n_load,1),tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The procedures
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// WBS zero+comb, procedure
procedure WBS_calib_fm {
    string band = "1a"; // HIFI band
}{
    //We shall always call these two blocks
    WBS0_fm(band);
    WBS_comb_fm(band);
    //
}

//TM to control heater values of LOU, procedure
procedure HL_heater_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band. ALL does all bands and all multipliers
    string context = "nominal" in ["nominal","stby"]; //whether heater applies to stby or nominal context
}{
    double[] cresult = CalibrationReader("name_loheater",["heater_nominal","heater_stby"],band,0.0);
    double hifi_HL_heater = cresult[0];
    if(context == "stby") {
        hifi_HL_heater = cresult[1];
    }
    Hifi_HIFI_HL_heater($BBID,hifi_HL_heater);
}

// HRS partial configuration, block
// Configures the LO and attenuators
block HRS_config_att_lo_w_lo_input_block_fm HIFI 3679 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["mr","mr"]; //HRS resolution code
    double[] hrs_subband = [5.0,5.0,5.0,5.0]; //Positions in IF of HRS sub-bands 1 and 2 for H/V
}{
    //Start_block();
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double hrsH_ATT_U1 = result[1]{0};
    double hrsH_ATT_L1 = result[2]{0};
    double hrsH_ATT_U2 = result[3]{0};
    double hrsH_ATT_L2 = result[4]{0};
    double hrsH_ATT_U3 = result[5]{0};
    double hrsH_ATT_L3 = result[6]{0};
    double hrsH_ATT_U4 = result[7]{0};
    double hrsH_ATT_L4 = result[8]{0};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double hrsV_ATT_U1 = result[1]{0};
    double hrsV_ATT_L1 = result[2]{0};
    double hrsV_ATT_U2 = result[3]{0};
    double hrsV_ATT_L2 = result[4]{0};
    double hrsV_ATT_U3 = result[5]{0};
    double hrsV_ATT_L3 = result[6]{0};
    double hrsV_ATT_U4 = result[7]{0};
    double hrsV_ATT_L4 = result[8]{0};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    //Update subbands 1 and 2 frequencies for H and V, and shift by half LO7 if wb mode
    double fshift = hrsH_LO[6] / 2000.0;
    //We assume that USB of wb mode will be used
    hrsH_LO[0] = hrs_subband[0] + fshift;
    hrsH_LO[1] = hrs_subband[1] + fshift;
    hrsV_LO[0] = hrs_subband[2] + fshift;
    hrsV_LO[1] = hrs_subband[3] + fshift;
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_ATT_U1,hrsH_ATT_L1,hrsH_ATT_U2,hrsH_ATT_L2,hrsH_ATT_U3,hrsH_ATT_L3,hrsH_ATT_U4,hrsH_ATT_L4,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
    // 
    //delay(hrs_config_delay);
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsV_ATT_U1,hrsV_ATT_L1,hrsV_ATT_U2,hrsV_ATT_L2,hrsV_ATT_U3,hrsV_ATT_L3,hrsV_ATT_U4,hrsV_ATT_L4,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
    // 
    delay(hrs_config_delay);
}

// Put system into pumped mixing state, i.e. init FPU and LO tuning
procedure Init_Mixing_proc_aot {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; // LO frequency in GHz
}{
    // At that stage we should just have switched on the LO
    sync();
    int startobs = time();
    // FPU setting at this frequency
    Init_MSA_aot(band,"CLOSE",lo_freq,true,"ON");
    // How long do we have to wait between LO switch-on and first tuning ?
    // The Init_MSA time is included in the delay
    double[] tunewait = CalibrationReader("tunetime",["lowarmup"],band,lo_freq * 1000.0);
    int rest = iceil(tunewait[0]) - (time() - startobs);
    delay(rest);
    //
    //LO power tuning: could use either H or V polar
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    double x = result[0]{0};
    string tuningbackend = "H";
    if(iround(x) == 2) {
        tuningbackend = "V";
    } else {
        tuningbackend = "H";
    }
    // Actually perform LO tuning
    LO_tuning_block_aot(band,lo_freq,lo_freq,tuningbackend,true,true,false);
}

/////////////////////////////////////////////////////////////////
// Procedure to compute the WBS IF levels for spectral scans
{bool,double[]} procedure TargetLevels {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    double[][] retunegrid = [[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]]; // dB grid
}{
    // Get target limits
    double[] limits = CalibrationReader("attenuator_levels",["sscan_max","sscan_min"],band,lo_freq);
    // Parameters of the field
    int nfreq = length(retunegrid);
    int nsub = length(retunegrid[0]);
    // Go through subbands - find maximum
    double[] maxfield = [];
    for(int i = 0 .. nsub - 1) {
        maxfield[i] = retunegrid[0][i];
        for(int j = 1 .. nfreq - 1) {
            maxfield[i] = max(retunegrid[j][i],maxfield[i]);
        }
    }
    // Renormalize
    for(int ii = 0 .. nsub - 1) {
        double norm = limits[0] / maxfield[ii];
        for(int jr = 0 .. nfreq - 1) {
            retunegrid[jr][ii] = norm * retunegrid[jr][ii];
        }
    }
    // search for minimum - use for target level
    double[] targetlevels = [];
    for(int jj = 0 .. nfreq - 1) {
        targetlevels[jj] = arraymin(retunegrid[jj]);
    }
    double absmin = arraymin(targetlevels);
    // Check for retuning needs
    bool retuning = absmin < limits[1];
    if(retuning) {
        message("Wide spectral range requires repeated backend tunings.<br>");
    }

    return {retuning,targetlevels};
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure FSwitch_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval limited by the data rates
    int data_time_off = 4; // data dump interval on OFF
    int n_per_on = 1; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int n_per_off = 1; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_loadinterval = 1; // number of nods before a load measurement
    int n_load_on = 0; // additional load measurements in ON pointing phase
    int n_load_off = 0; // additional load measurements in OFF pointing phase
    bool end_load_on = false; // Need for load after ON pointing phase
    bool end_load_off = false; // Need for load after OFF pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int loadlength = 50; // Load duration
    int shiftlength = 0; // Shift of the loop start relative to the pointing
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] onrates = dataparms{1};
    dataparms = DataTaking(backendreadoutparms,data_time_off);
    double[] offrates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFIFsw(band,lo_freq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength + shiftlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
            if(shiftlength > 0) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 7) {
            // The NOD-state represents our OFF position
            HIFIConfigureFSwitchIntegration(data_time_off,n_per_off,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i1 = 1 .. n_load_off) {
                HIFIFSwitchOffIntegration(data_time_off,n_per_off,band,lo_freq,offrates);
                // Perform load calibration
                delay(readoutdead);
                DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureFSwitchIntegration(data_time_off,n_per_off,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFIFSwitchOffIntegration(data_time_off,n_per_off,band,lo_freq,offrates);
            // Second phase on OFF
            // occurs for even cycle numbers
            runintostate = false;
            if(state[2] % 2 == 0) {
                if(end_load_off) {
                    delay(readoutdead);
                    DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 3) {
            // The POINT-state represents our source position
            HIFIConfigureFSwitchIntegration(data_time,n_per_on,band,lo_freq,backendreadoutparms);
            // ON integration
            // Loop for load cycles
            for(int i2 = 1 .. n_load_on) {
                HIFIFSwitchOnIntegration(data_time,n_per_on,band,lo_freq,onrates);
                // Perform load calibration
                delay(readoutdead);
                DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureFSwitchIntegration(data_time,n_per_on,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFIFSwitchOnIntegration(data_time,n_per_on,band,lo_freq,onrates);
            // First phase in source
            // occurs for odd cycle numbers
            runintostate = false;
            if(state[2] % 2 == 1) {
                if(end_load_on) {
                    delay(readoutdead);
                    DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
        }
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                // ( Does not occur if end_load is set)
                DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

//Fast readout of diplexer currents, block
block Diplexer_engineering_scan_block_fm HIFI 3696 {
    string mixer_polarization = "H" in ["H","V"]; //Polarization to be scanned
    double diplexer_C = 0.0; // Value of the diplexer current to move to
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50]; //Samples before movement
    int samplesAfter = 1000 in [0,1000]; //Samples after movement
}{
    Start_block();
    if(mixer_polarization == "H") {
        Hifi_HIFI_DiplexerH_scan_fast(milliSecSample,diplexer_C,samplesBefore,samplesAfter);
    } else {
        Hifi_HIFI_DiplexerV_scan_fast(milliSecSample,diplexer_C,samplesBefore,samplesAfter);
    }
    //Compute delay for scan
    int nb_HK = 2;
    //For this TC, the last HK field is blanked out
    int millisecondsUsed = 1000 + 10 + milliSecSample * nb_HK * (samplesBefore + samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
}

////////////////////////////////////
// Special DBS raster  - cross observing mode
// 
{string,double,double}[] procedure HifiMappingProcDBSCrossSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the two raster lines
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // inherit from dbs-raster mode
    {string,double,double}[] retvalues = HifiMappingProcDBSRasterSequencerInit(naifid,ra,dec,{0.0,double(npoints / 2) * stepsize},2,stepsize,npoints,band,lo_freq,effResolution,continuumDetection,oneGHzReference,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);

    return retvalues;
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure OTFDoubleChopNoRef_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int nlines = 20; // Number of lines in the map
    int npoints = 20; // Number of points in the map
    int n_cycles = 1; // Number of map coverages
    bool fs = false; // whether frequency switch used
    double tscan = 10.0; // Total average duration of one scan
    double tdead = 0.05; // Average dead time in one chop cycle
}{
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    double idealnoise = idealvalues{1} * idealvalues{1};
    double obsnoise = noisevalues{0} * noisevalues{0};
    // rescale for map coverage
    idealnoise = idealnoise * double(npoints * nlines);
    double efficiency = idealnoise / obsnoise;
    // Compute the actual integration time
    double posinttime = double(n_cycles * nlines * npoints) * (tscan - tdead);
    double posofftime = 0.0;
    int instrumenttime = iceil(double(n_cycles * nlines * npoints) * tscan);
    // Check total integration time
    double timeefficiency = (posinttime + posofftime) / double(totaltime);
    // Noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // Non-standard messages
    message("</p><p>");
    message("The observed map consists of " + nlines + " OTF lines, each covering " + npoints + " readout points.<br>");
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posofftime,timeefficiency,efficiency,relnoise,fs);
}

//Procedure computing the maximum time for LO configuration
// over a given SScan range relative to the time at a reference frequency
//
int procedure ComputeLOTimeDifference {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    double reffreq = 978200.0; // Reference frequency
}{
    // Translate MHz from AOT API to configuration table in GHz
    double lofreq_ref = reffreq / 1000.0;
    double lofreq_min = lo_freq / 1000.0;
    double lofreq_max = lo_freq_up / 1000.0;
    //Some sanity checks
    if(lofreq_min >= lofreq_max) {
        error("Min LO frequency for SScan is higher than max one");
    }
    //Get safe Vd2 value for this LO subband
    double[] cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lofreq_ref);
    double drain2_safe = cresult[0];
    //Get tuning delays
    {double,string}[] result = ConfigurationReader("name_delays",["lock_lo_delay","vd2_rampup_speed"],band,lofreq_ref);
    double lock_lo_delay = result[0]{0};
    double vd2_rampup_speed = result[1]{0};
    // Reference value
    double tune_range_factor = 1.05;
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlcutune = "name_configlcutune_b";
    }
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lofreq_ref);
    //Value must be clipped to blue max
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq / 1000.0);
    int ref_delay = iceil(lock_lo_delay + (min(result[0]{0},drain2_bluemax) * tune_range_factor - drain2_safe) / vd2_rampup_speed);
    //Readout content of LCU Vd2 table only once out of loop
    string tab = "configlcu" + band + "tune.config";
    double[] allVd2 = dcolumn(tab,"drain2_v");
    //Determine bracketting indices
    int index_min = ibracket(tab,"index",lofreq_min);
    int index_max = ibracket(tab,"index",lofreq_max);
    //Loop on all bracketted indices
    double max_vd2 = 0.0;
    for(int i = index_min .. index_max) {
        max_vd2 = max(allVd2[i],max_vd2);
    }
    // Maximum value
    int delay_max = iceil(lock_lo_delay + (max_vd2 * tune_range_factor - drain2_safe) / vd2_rampup_speed);
    // Return difference by which the duration has to be corrected

    return delay_max - ref_delay;
}

// active HK while instrument is not integrating
block HIFIActiveHK HIFI 6002 {
    string speed = "normal" in ["fast","normal","slow"]; // Select HK rate
    int period = 10; //  Time for which active HK is to be used
}{
    // Compute active period
    int aperiod = period - 4;
    // Get parameters
    {string,int,double,double,double,double} hkparms = PeriodicHKParms(speed);
    // ignored if time is too short
    if(aperiod > hkparms{1}) {
        // initial delay
        delay(2);
        // Correct for additional readouts
        double numreadout = double(aperiod / hkparms{1});
        double enhance = (1.0 + numreadout) / numreadout;
        // Active HK
        string[] pattern = QueryHKPattern(true);
        non_ess_hk_data_rate(enhance * hkparms{3} / 1024.0);
        ess_hk_data_rate(enhance * hkparms{5} / 1024.0);
        Hifi_HIFI_Housekeeping_on(hkparms{0},pattern[0],pattern[1],pattern[2],pattern[3],pattern[4],pattern[5]);
        delay(aperiod);
        // Back to passive HK
        pattern = QueryHKPattern(false);
        non_ess_hk_data_rate(hkparms{3} / 1024.0);
        ess_hk_data_rate(hkparms{5} / 1024.0);
        Hifi_HIFI_Housekeeping_on(hkparms{0},pattern[0],pattern[1],pattern[2],pattern[3],pattern[4],pattern[5]);
        delay(2);
    } else {
        delay(period);
    }
}

//HIFI vector scan investigation, block
//Check vector scan from safe to values close to BLUE MAX
block Vecscan_Investigation_block_fm HIFI 3972 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    int pretime = 5 in [0,10]; // time between preamble and scan, if < 4, no preamble	
    double step_time = 5.0 in [4.0,10.0]; // time between steps in scan
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    drain2_v_start = drain2_safe;
    //
    double drain2_max = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //For bands 1 to 5, scan will be done with increasing drain2 voltages
    //
    //For bands 6 to 7, scan will be done with decreasing drain2 voltages: NOT FOR THIS TEST !!
    if(band == "6a" || band == "7a" || band == "6b" || band == "7b") {
        //step_drain2_v = -1.0*step_drain2_v;
        //drain2_v_start = drain2_max;
        //Also, it probably makes no sense to go down to the safe value
        drain2_v_start = drain2_safe + 0.45;
        //i.e. go to 1.7
        //Need to check that drain2_v_start has not got above the blue max
        //If so, the range to scan is not so big so we stick to the safe value
        //as minimum drain2 for the scan
        if(drain2_v_start >= drain2_max) {
            drain2_v_start = drain2_safe;
        }
    }
    //
    result = ConfigurationReader(name_configlotune,["nsteps","step_time"],band,lo_freq);
    int nsteps = iround(result[0]{0});
    double step_drain2_v = -1.0 * (drain2_max - drain2_v_start) / double(nsteps - 1);
    drain2_v_start = drain2_max;
    // double step_time = steptime ;	//result[1]{0};
    //
    //Preamble tuning macro to highest Vd2 of the upcoming scan
    result = ConfigurationReader("name_delays",["lock_lo_delay","vd2_rampup_speed"],band,lo_freq);
    int config_lo_delay = iceil(result[0]{0} + (drain2_v_start - drain2_safe) / result[1]{0});
    //
    // override by parameter value
    if(pretime >= 4) {
        config_lo_delay = pretime;
        HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    }
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    //delay(1);
    //Execute vector scan 
    Hifi_HIFI_vector_scan($BBID);
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//////////////////////////////////////////////////////////////////
// HRS complete configuration with maximum attenuation, block
// Both polarizations are treated
block HRS_standby_block_fm HIFI 3633 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    //Start_block();
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrh_up_ol1_m = a_m_parameter[1];
    int hrh_up_ol1_a = a_m_parameter[0];
    int hrh_up_ol2_m = a_m_parameter[3];
    int hrh_up_ol2_a = a_m_parameter[2];
    int hrh_up_ol3_m = a_m_parameter[5];
    int hrh_up_ol3_a = a_m_parameter[4];
    int hrh_up_ol4_m = a_m_parameter[7];
    int hrh_up_ol4_a = a_m_parameter[6];
    int hrh_down_ol5_m = a_m_parameter[9];
    int hrh_down_ol5_a = a_m_parameter[8];
    int hrh_down_ol6_m = a_m_parameter[11];
    int hrh_down_ol6_a = a_m_parameter[10];
    int hrh_down_ol7_m = a_m_parameter[12];
    //V-polar
    int hrv_up_ol1_m = a_m_parameter[14];
    int hrv_up_ol1_a = a_m_parameter[13];
    int hrv_up_ol2_m = a_m_parameter[16];
    int hrv_up_ol2_a = a_m_parameter[15];
    int hrv_up_ol3_m = a_m_parameter[18];
    int hrv_up_ol3_a = a_m_parameter[17];
    int hrv_up_ol4_m = a_m_parameter[20];
    int hrv_up_ol4_a = a_m_parameter[19];
    int hrv_down_ol5_m = a_m_parameter[22];
    int hrv_down_ol5_a = a_m_parameter[21];
    int hrv_down_ol6_m = a_m_parameter[24];
    int hrv_down_ol6_a = a_m_parameter[23];
    int hrv_down_ol7_m = a_m_parameter[25];
    //Attenuators are fixed
    //H-polar
    double hrh_1u_att = 15.5;
    double hrh_1l_att = 15.5;
    double hrh_2u_att = 15.5;
    double hrh_2l_att = 15.5;
    double hrh_3u_att = 15.5;
    double hrh_3l_att = 15.5;
    double hrh_4u_att = 15.5;
    double hrh_4l_att = 15.5;
    //V-polar    
    double hrv_1u_att = 15.5;
    double hrv_1l_att = 15.5;
    double hrv_2u_att = 15.5;
    double hrv_2l_att = 15.5;
    double hrv_3u_att = 15.5;
    double hrv_3l_att = 15.5;
    double hrv_4u_att = 15.5;
    double hrv_4l_att = 15.5;
    //Configure HRS-H
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrh_1u_att,hrh_1l_att,hrh_2u_att,hrh_2l_att,hrh_3u_att,hrh_3l_att,hrh_4u_att,hrh_4l_att,hrh_up_ol1_m,hrh_up_ol1_a,hrh_up_ol2_m,hrh_up_ol2_a,hrh_up_ol3_m,hrh_up_ol3_a,hrh_up_ol4_m,hrh_up_ol4_a,hrh_down_ol5_m,hrh_down_ol5_a,hrh_down_ol6_m,hrh_down_ol6_a,hrh_down_ol7_m);
    //delay(hrs_config_delay);
    //
    //Configure HRS-V
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrv_1u_att,hrv_1l_att,hrv_2u_att,hrv_2l_att,hrv_3u_att,hrv_3l_att,hrv_4u_att,hrv_4l_att,hrv_up_ol1_m,hrv_up_ol1_a,hrv_up_ol2_m,hrv_up_ol2_a,hrv_up_ol3_m,hrv_up_ol3_a,hrv_up_ol4_m,hrv_up_ol4_a,hrv_down_ol5_m,hrv_down_ol5_a,hrv_down_ol6_m,hrv_down_ol6_a,hrv_down_ol7_m);
    delay(hrs_config_delay);
    //
    //Now Configure blocks
    HRS_config_resol_fm(band,hrs_mode);
}

//HIFI-COP-2.1-DipCal2
procedure Diplexer_calibration_hotcold_COP_proc_ops {
    string band = "3" in ["3","4","6","7"]; // HIFI mixer band
}{
    //
    //Get the list of frequencies to be used for the scan
    string tab = "configdipcalib_" + band + ".config";
    int total = table_size(tab);
    double[] freq = [];
    string[] subband = [];
    for(int j = 1 .. total) {
        freq[j] = dlookup(tab,"" + j,"frequency");
        subband[j] = slookup(tab,"" + j,"subband");
        //Check whether this combination of band+freq is allowed in the current CUS
        Check_Band_vs_Freq_proc_fm(subband[j],freq[j]);
    }
    string current_subband = "0";
    //Start loop on diplexer scans
    for(int i = 1 .. total) {
        //
        //First check whether one needs to switch on another LO band
        if(subband[i] != current_subband) {
            LCU_switchon_proc_fm(subband[i]);
            //Wait an extra delay of 1 min for short term stabilization
            delay(60);
            current_subband = subband[i];
        }
        Diplexer_calibration_hotcold_proc_fm(subband[i],freq[i]);
    }
    //
}

// Get actual frequency throw best suited for the LO band
double procedure GetTrueFsThrow {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    string throwstring = "small-negative"; // Frequency throw identifier
}{
    // perform lookup
    double[] throw = CalibrationReader("fsthrows",[throwstring],band,lo_freq);

    return throw[0];
}

//
// Chopper scan without spectra, block
block Chopper_scan_nospectra_fm HIFI 3261 {
    string band = "1a"; // HIFI band
    double chopper_pos_min = -7.0; //minimum chopper position
    double chopper_pos_max = 8.0; //maximum chopper position
    int n_steps = 300; //number of steps
}{
    Start_block();
    //
    int steps = 0;
    int steps_done = 0;
    int steps_wanted = n_steps;
    if(steps_wanted < 1) {
        steps_wanted = 1;
    }
    double chopper_pos = 0.0;
    double stepsize = 0.0;
    if(steps_wanted > 1) {
        stepsize = (chopper_pos_max - chopper_pos_min) / (double(steps_wanted) - 1.0);
    }
    //Move first half way to the first scanned position to
    //avoid hitting the end stop
    double intermediate_chopper_pos = (chopper_pos_max + chopper_pos_min) / 2.0;
    intermediate_chopper_pos = Check_Chopper_Prime_Redundant(intermediate_chopper_pos);
    HIFI_CPR_Chopper_Rot_proc_fm(intermediate_chopper_pos);
    //Rotate chopper
    Hifi_HIFI_non_periodic_hk_FCU();
    //To get sent voltage
    delay(1);
    //
    while(steps_done < steps_wanted) {
        steps = steps_wanted - steps_done;
        if(steps > n_steps) {
            steps = n_steps;
        }
        chopper_pos = chopper_pos_min + double(steps_done) * stepsize;
        if(chopper_pos > 8.5) {
            chopper_pos = 8.5;
            //Cannot go over 8.5 Volts
        }
        //
        chopper_pos = Check_Chopper_Prime_Redundant(chopper_pos);
        HIFI_CPR_Chopper_Rot_proc_fm(chopper_pos);
        //Rotate chopper
        Hifi_HIFI_non_periodic_hk_FCU();
        //To get sent voltage
        delay(1);
        steps_done = steps_done + 1;
    }
}

// FPU settling time for a mixer band change, procedure
procedure FPU_Settling_time_proc_fm {
    string band_1 = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string band_2 = "2a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int int_time1 = 3600; //Integration time after first tuning
    int int_time2 = 600; //Integration time after first and second switch
    double lo_freq_1 = 500.0; //LO frequency in sub-band a
    double lo_freq_2 = 700.0; //LO frequency in sub-band b
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //
    //Get cold position
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["chop_cold"],band_1,0.0);
    double chop = result_d[0]{0};
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band_1);
    }
    //Set up mixer for lo_freq_1
    Init_MSA_fm(band_1,"CLOSE",lo_freq_1,"ON");
    FPU_Settling_time_first_tuning_fm(band_1,int_time1,lo_freq_1,backend);
    //
    Init_MSA_fm(band_2,"CLOSE",lo_freq_2,"ON");
    FPU_Settling_time_second_tuning_fm(band_2,int_time2,lo_freq_2,backend);
    //
    Init_MSA_fm(band_1,"CLOSE",lo_freq_1,"ON");
    FPU_Settling_time_third_tuning_fm(band_1,int_time2,lo_freq_1,backend);
    //
}

/////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing for a
// Spectral Scan Load-Chop observing mode
// 
// We assume that each telescope motion is related to an
// instrument calibration.
// 
{{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} procedure SScanLoadChop_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq_low = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4; // Frequency scan redundancy
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_chop_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_chop_off = 1 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Create composite readout structure for backends
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get frequency grid characteristic parameters
    {int,double,double[],int[][],int,bool} fqparms = MakeFreqGrid(band,lo_freq_low,lo_freq_up,redundancy,0.0,n_freq_point);
    double reffreq = fqparms{1};
    double[] freqgrid = fqparms{2};
    int[][] grouporder = fqparms{3};
    // Process tuning level grid
    double[][] levelgrid = GetSScanLevelGrid(band,wbs1,wbs2,freqgrid,fqparms{0},grouporder);
    {bool,double[]} targets = TargetLevels(band,reffreq,levelgrid);
    bool retuning = targets{0};
    double[] targetgrid = targets{1};
    string reftarget = "";
    if(retuning) {
        reftarget = "sscan_normal";
    }
    {int,double,double[],int[][],bool,double[],int,bool} spectralparms = {fqparms{0},reffreq,freqgrid,grouporder,retuning,targetgrid,fqparms{4},fqparms{5}};
    //////////////////////////////////////////////////////////////////////
    // Compute load integration time
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,reffreq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    int jitterdead = GetMaxTimeJitter(band,reffreq);
    // Integration time per frequency and pointing
    int on_inttime = 2 * n_chop_on * data_time;
    int off_inttime = 2 * n_chop_off * data_time_off;
    // Duration of initial set up
    // Staying at the same frequency makes no sense here. 
    // First frequency point
    double runningfreq = freqgrid[grouporder[1][0]];
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,runningfreq,hrs1,hrs2,wbs1{0},wbs2{0},"sscan_normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,runningfreq,false);
    }
    initlength = initlength + loadlength;
    // Tuning delays
    int bigtunestep = duration(HIFIRetuneFreq(band,reffreq,reftarget));
    // Correct for variation within the band
    int tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq);
    bigtunestep = bigtunestep + tunediff;
    // As step within a group could be faster than a large step 
    if(n_freq_point > 1) {
        int smallstep = duration(HIFIChangeFreq(band,reffreq));
    } else {
        smallstep = bigtunestep;
    }
    // For double phases I can use the added jitterdead in both phases for tune
    int auxtunestep = bigtunestep - jitterdead;
    int halftunestep = (auxtunestep + 1) / 2;
    // Telescope pointing
    int on_pointing = n_freq_point * on_inttime + (n_freq_point - 1) * smallstep + halftunestep + jitterdead;
    int off_pointing = off_inttime + halftunestep + jitterdead;
    // Check load_interval allowance
    int scan_time = 2 * imax(on_pointing,off_pointing);
    if(scan_time > load_spacing) {
        SError("Load interval of " + load_interval + "s is exceeded by " + n_chop_on * n_freq_point + " chop cycles.");
    }
    // Estimate of the load-cycles to issue a representative 
    // telescope command
    if(n_cycles > 1) {
        // How often do I have to perform a load slew
        int n_loadinterval = imax(load_interval / scan_time,1);
        // fit with n_cycles
        n_loadinterval = imin(n_loadinterval,n_cycles);
        n_loadinterval = IMultiple(n_loadinterval,n_cycles);
    } else {
        n_loadinterval = 1;
    }
    // recompute load length during slews in case of short integrations
    // This regime must be maintained in the post_timing
    if(n_loadinterval <= 1) {
        loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,false,eff_resolution{0},data_time,backendreadoutparms));
        loadlength = loadlength + readoutdead;
    }
    // No dangling needed in this mode - we stop halftunelength before telescope
    int dangling = 0;
    bool end_load_on = false;
    bool end_load_off = false;
    // Return all the times needed for telescope call and post_timing processing

    return {{on_inttime,off_inttime,on_pointing,off_pointing,loadlength,auxtunestep,load_spacing,n_loadinterval,n_chop_on,n_chop_off,data_time,data_time_off,end_load_on,end_load_off,initlength,dangling},spectralparms};
}

// Chopper scan without spectra, procedure
// Look at effective current in function of commanded chopper position
procedure Chopper_scan_nospectra_proc {
    string band = "1a"; // HIFI band		//Setting file
    double chopper_pos_min = -7.0; //minimum chopper position
    double chopper_pos_max = 8.0; //maximum chopper position
    int n_steps = 300; //number of steps
}{
    //
    Chopper_scan_nospectra_fm(band,chopper_pos_min,chopper_pos_max,n_steps);
    //
}

// Broadcast OBSID
block BroadcastOBSID_no_hk_request HIFI 902 {
}{
    //These are ILT-EGSE commands, not ruled by the 2TC/sec.
    //HifiIltEgse_PDU_set_OBS_ID($OBSID);
    //HifiIltEgse_PDU_set_BB_ID($BBID);
    //delay(1);
    //HifiIltEgse_FPU_set_OBS_ID($OBSID);
    //HifiIltEgse_FPU_set_BB_ID($BBID);
    //delay(1);
    //SpireIltEgse_QCC_SETOBSID($OBSID);
    //SpireIltEgse_QCC_SETBBID($BBID);
    //delay(1);
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    //Hifi_HIFI_non_periodic_hk_FCU();
    delay(1);
}

// Detector heater control
block Heater_fm HIFI 3240 {
    string band = "1a";
}{
    //Start_block();
    //Get name of FPU configuration file
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["normal_heater_time_h","normal_heater_time_v","heater_delay_h","heater_delay_v","magnet_current_max_h","magnet_current_max_v"],band,0.0);
    double normal_heater_time_h = result_d[0]{0};
    double normal_heater_time_v = result_d[1]{0};
    int heater_delay_h = iround(result_d[2]{0});
    int heater_delay_v = iround(result_d[3]{0});
    //Magnets need to be switched to 0 prior to the deflux
    Hifi_HIFI_CH1_MX_MG_C($BBID,0.0);
    Hifi_HIFI_CV1_MX_MG_C($BBID,0.0);
    delay(1);
    //
    mois_tmcheck("In the 2 seconds following the upcoming TC, parameter HF_AH1_DHTR_C should increase in the vicinity of 17mA, then drop to its initial value.");
    Hifi_HIFI_HF_CH1_DHTR_C($BBID,normal_heater_time_h);
    delay(iceil(normal_heater_time_h / 1000.0) + 1);
    //
    //Extra delay for cooling down temperature: will be included in the V-mixer delay
    //delay(heater_delay_h);
    mois_tmcheck("In the 2 seconds following the upcoming TC, parameter HF_AV1_DHTR_C should increase in the vicinity of 17mA, then drop to its initial value.");
    Hifi_HIFI_HF_CV1_DHTR_C($BBID,normal_heater_time_v);
    delay(iceil(normal_heater_time_v / 1000.0) + 1);
    //Extra delay for cooling down temperature: both mixers cool down together
    delay(heater_delay_v);
    //
    //Set back magnet to nominal
    //First set magnets to max.
    double magnet_current_max_h = result_d[4]{0};
    double magnet_current_max_v = result_d[5]{0};
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_current_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_current_max_v);
    delay(1);
    //Nominal values
    //Need a representative frequency: take keyfreq
    //At that stage, band 8 needs to be treated as band 3 to solve SPR-2316
    if(band == "8") {
        band = "3a";
    }
    double[] result = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result[0];
    //
    result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
    double magnetcurrent_H = result_d[0]{0};
    double magnetcurrent_V = result_d[1]{0};
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnetcurrent_H);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnetcurrent_V);
    delay(1);
}

/////////////////////////////////////////////////////////////////
// get reference frequency, resolution, redundancy 
{{bool,int,double[],bool[]},{bool,int,double[],bool[]}} procedure GetSpectralScanHRS {
    int redundancy = 4; // Redundancy of overall spectral scan
    string band = "4a"; // HIFI band
}{
    string calibfile = "spectralscan_hrs";
    string sredun = "" + redundancy;
    // Use generic reader
    double[] hrsset = SpectralScanReader("fscanhrs",["resolution","hrs1_offset","hrs2_offset"],band,redundancy);
    int hrsresol = iround(hrsset[0]);
    double hrs1_offset = hrsset[1];
    double hrs2_offset = hrsset[2];
    // Fill into normal structure
    double[][] hrspositions = SpreadHRS(band,[hrsresol,hrsresol],[hrs1_offset,hrs2_offset]);
    {bool,int,double[],bool[]} hrs1 = {true,hrsresol,hrspositions[0],[true,true,true,true]};
    {bool,int,double[],bool[]} hrs2 = {true,hrsresol,hrspositions[1],[true,true,true,true]};

    return {hrs1,hrs2};
}

//Check consistency between band and frequency inputs
//Should be invoked at the beginning of every mode !
bool procedure Check_Band_vs_WarmKeyFreq_proc_fm {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band   
    double lo_freq = 500.0; //LO frequency
}{
    bool go_ahead_warm = true;
    //For LOU FM warm operations, only 1 freq allowed per band
    //This frequency is tabulated as keyfreqwarm
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreqwarm"],band,0.0);
    double lo_freq_keywarm = result_d[0];
    double margin = 0.24;
    //margin allowed for FSW in all bands but 4
    if(band == "4a" || band == "4b") {
        margin = 1.0;
    }
    if(lo_freq < lo_freq_keywarm - margin || lo_freq > lo_freq_keywarm + margin) {
        error("LO frequency not in list of allowed frequencies for warm operations in band " + band);
        go_ahead_warm = false;
    }
    //}

    return go_ahead_warm;
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure SScanDBS_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int nfreq = 4; // Number of frequency points per IF
    bool dsb = true; // Both sidebands covered
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int allsteps = 4; // Total number of frequency pointing periods
    int freqsteps = 4; // Total number of frequencies
    double avnumchop = 1.0; // Average number of chop cycles per frequency
    double tscan = 60.0; // Total average duration of one cycle
    {double,double,double} tact = {10.0,4.9,0.05}; // Field of actual dead and integration times
}{
    double inttimeperphase = tact{1};
    // Actual integration time in one phase
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    // Use DSB noise for long spctral scans
    if(dsb) {
        double idealnoiselsb = idealvalues{1} * idealvalues{1};
        double idealnoiseusb = idealvalues{3} * idealvalues{3};
        double idealnoise = idealnoiselsb * idealnoiseusb / (idealnoiselsb + idealnoiseusb);
    } else {
        idealnoise = idealvalues{1} * idealvalues{1};
    }
    double obsnoise = noisevalues{0} * noisevalues{0};
    // rescale for range coverage
    double accumulation = double(freqsteps) / double(nfreq);
    idealnoise = idealnoise * accumulation;
    double efficiency = idealnoise / obsnoise;
    // Compute the actual integration time
    double maxsteps = max(double(freqsteps),double(allsteps));
    double posinttime = maxsteps * inttimeperphase * 2.0 * avnumchop;
    int instrumenttime = iceil(double(allsteps) * tscan);
    // Check total integration time
    double timeefficiency = 2.0 * posinttime / double(totaltime);
    // Noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posinttime,timeefficiency,efficiency,relnoise,dsb);
}

//Slow chopped hotcold, block
block Hot_cold_slowchop_fm HIFI 3224 {
    string band = "1a";
    int integ_time = 8; //Total integration time for delay computation
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,etc
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast 
}{
    //Start_block(); 
    //Rotate chopper: assume we come from M3: no rotation as this is done in the slowchop_spectro
    //Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_hot_ang");
    //Fetch respective chopper angles
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_hot","chop_cold"],band,0.0);
    double chop_hot = result[0]{0};
    double chop_cold = result[1]{0};
    //
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"slowchop",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    HIFI_Spectr_slow_chop_proc_fm(chop_hot,chop_cold);
    Apply_Slow_Chop_delay(integ_time,band,backend);
    delay(1);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// Get frequency resolution needed to measure standing wave pattern
// in chop measurements
double procedure GetChopSWResolution {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] dead = CalibrationReader("chopswresolution",["resolution"],band,lo_freq);

    return dead[0];
}

//Procedure checking whether commanded voltage is in the acceptable range
double procedure Check_Chopper_Range {
    double chopper_angle = 0.0; //prime or redundant chopper voltage
}{
    //Check prime or redundant status
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant","prime_endstop_min","prime_endstop_max","red_endstop_min","red_endstop_max"],"0",0.0);
    double chop = chopper_angle;
    double prime_endstop_min = result_d[1]{0};
    double prime_endstop_max = result_d[2]{0};
    double red_endstop_min = result_d[3]{0};
    double red_endstop_max = result_d[4]{0};
    //
    //Checks the chopper angle is within the ranges
    if(result_d[0]{1} == "prime") {
        if(chop > prime_endstop_max || chop < prime_endstop_min) {
            error("The chopper voltage (requested is " + chop + " V) in " + result_d[0]{1} + " mode has to be between " + prime_endstop_min + " and " + prime_endstop_max + " V.");
        }
    }
    if(result_d[0]{1} == "redundant") {
        if(chop > red_endstop_max || chop < red_endstop_min) {
            error("The chopper voltage (requested is " + chop + " V) in " + result_d[0]{1} + " mode has to be between " + red_endstop_min + " and " + red_endstop_max + " V.");
        }
    }

    return chop;
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure JupiterDBS_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size 
    int n_seq = 1; // Number of continuous chop cycles
    int n_load = 0; // additional load measurements in one pointing phase
    int n_loadinterval = 10; // number of nods before a load measurement
    bool end_load = false; // Need for load after each pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    int shiftlength = 10; // Shift of the loop start relative to the pointing
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"jupiter");
            }
            delay(tinitslew - (time() - startobs) - loadlength + shiftlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            if(shiftlength > 0) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i1 = 1 .. n_load) {
                HIFISlowChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFISlowChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
            // Second phase in first nod position
            // occurs for even cycle numbers
            runintostate = false;
            if(state[2] % 2 == 0) {
                if(end_load) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // A nod slew follows - active HK if not used by load measurement
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 7) {
            // second nod position
            HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i2 = 1 .. n_load) {
                // Use asymmetric scheme now to minimize setup uncertainties
                HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
            // First phase in second nod position
            // occurs for odd cycle numbers
            runintostate = false;
            if(state[2] % 2 == 1) {
                if(end_load) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // A nod slew follows - active HK if not used by load measurement
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
        }
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                // ( Does not occur if end_load is set)
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

//TM to control heater values of LOU, block
block HL_heater_block_fm HIFI 3615 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band. ALL does all bands and all multipliers
    string context = "nominal" in ["nominal","stby"]; //whether heater applies to stby or nominal context
}{
    double[] cresult = CalibrationReader("name_loheater",["heater_nominal","heater_stby"],band,0.0);
    double hifi_HL_heater = cresult[0];
    if(context == "stby") {
        hifi_HL_heater = cresult[1];
    }
    Hifi_HIFI_HL_heater($BBID,hifi_HL_heater);
}

//Check frequencies are not separated by more than one index
procedure Check_FSW_index_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq_1 = 500.0; //LO frequency FSW1
    double lo_freq_2 = 501.0; //LO frequency FSW2
}{
    //Fetch LO parameters
    string name_confindex = "name_confindex_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_confindex = "name_confindex_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq_1);
    int freq_nx_1 = ifloor(result[0]{0});
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq_2);
    int freq_nx_2 = ifloor(result[0]{0});
    //
    if(abs(double(freq_nx_1 - freq_nx_2)) > 1.0) {
        error("The frequencies are separated by more than 1 index. Please reduce the throw.");
    }
}

//////////////////////////////////////////////////////////////////////////
// special setup using the new frequency calibration - to be removed again
//////////////////////////////////////////////////////////////////////////
// Procedure for zero and comb measurement 
// Collects all common parts for LoadMeasurement and DoubleLoadMeasurement
//
procedure ZeroCombMeasurement_FCal {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double lo_freq = 978200.0; // LO frequency
    int used_datatime = 4; // time between subsequent data readouts in load
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
}{
    // Usage of WBS
    bool wbs1used = backendreadoutparms{2}{0};
    bool wbs2used = backendreadoutparms{3}{0};
    // Zero and Comb measurement is only used in WBS observations
    if(wbs1used || wbs2used) {
        // Now start the zero-comb measurement
        int danglingreadout = WBS_Zero_FCal(band,lo_freq);
        // Add possible delay needed before next zero measurement
        if(used_datatime < danglingreadout) {
            delay(danglingreadout - used_datatime);
        }
    }
}

//General LO configuration command
block HIFI_Configure_LCU_block_fm HIFI 3617 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    int freq_nx = 0; // HL_freq_nx
    int lsu_main = 0; // HL_LSU_main
    int lsu_offset = 0; // HL_LSU_offset
    int d2_step = 1; // HL_D2_step
    double plevel_v = 0.0;
    double m1_v = 9.0;
    double m2_v = -2.0;
    double m3_v = 0.0;
    double gate1_v = -2.5;
    double gate2_v = -2.5;
    double drain1_v = 2.8;
    string curlim1_v = "1.4";
    double drain2_v = 2.6;
    string curlim2_v = "1.4";
    int macro_checksum = 0; // HL_macro_checksum
    int config_lo_delay = 6;
}{
    //Check that Vd2 is within the blue limits
    drain2_v = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v);
    //
    //Start_block(); 
    //
    //Execute configuration
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_safe_LCU_ch1a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_safe_LCU_ch1b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_safe_LCU_ch2a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_safe_LCU_ch2b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_safe_LCU_ch3a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_safe_LCU_ch4a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_safe_LCU_ch4b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
    delay(config_lo_delay);
    //
    //Store settings into available register
    //HIFI_HL_store_tm_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

{int,double,double,double,double,double} obs HifiPointModePositionSwitch {
    string modeName = "pos";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,5]; // data dump interval limited by the data rates
    int n_int_on = 3 in [2,1800]; // number of data dumps for integration per phase
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Single Point - Position Switch",{data_time,0,n_int_on,0,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} pre_timing = PositionSwitch_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},double,double} post_timing = PositionSwitch_post_timing(pre_timing,telescopetimes,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,post_timing{1},n_cycles);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    int loadlength = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{7};
    bool final_load = post_timing{1}{12};
    double tscan = post_timing{2};
    double tdead = post_timing{3};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        PositionSwitch_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,startobs,telescopetimes,n_loadinterval,loadlength,final_load);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    double tdead_tot = PositionSwitch_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = PositionSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_cycles,tscan,tdead_tot);
    // Evaluate performance
    PositionSwitch_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,tscan,tdead_tot);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Stability test, procedure
// Measurement of external cold only
procedure Proc_stability_extcold {
    string band = "1a"; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string obsmode = "fastchop" in ["fastchop","tp"]; //Whether to use tp or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    //
    Chopper_Rotation_block_fm(band,"chop_hot_ang","chop_M3_ang");
    //Look at M3
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        //Configure and tune backends
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration: done later
    //Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);	//2 sec. integration
    //
    Stability_extcold_fm(band,n,integ_time,backend,hrs_mode,obsmode,chop_phase);
    //Configure spectrometers integration back to default
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
}

////////////////////////////////////
// Frequency switch observing mode without baseline calibration
// 
// All properties inherited from the load-chop mode
//
// This whole implementation is highly speculative as we have no experience
// with frequency switch measurements yet.
//
{int,double,double,double,double,double} obs HifiPointProcFSwitchNoRef {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_cycles = 2 in [1,3600]; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Single Point - Frequency Switch noRef",{data_time,0,0,0,0,0,0,0,n_cycles,load_interval});
    // Two cases: fine pointing or position switch
    // Call first part of the timing computer
    {int,int,int,int,int,int,bool,int,int} pre_timing_f = FSwitchNoRef_pre_timing(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_cycles,load_interval,docommands);
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,double,double,int} tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,pre_timing_f);
    // Dummy call to spacecraft command
    int[] telescopetimes = basic_fine_pointing(false,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,bool,int,int},double,double} post_timing_f = SingleChopNoRef_post_timing(pre_timing_f,telescopetimes);
    // Now the actual observation starts
    // Prepare telescope command
    tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,post_timing_f{1});
    // Call telescope command 
    telescopetimes = basic_fine_pointing(true,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
    // Consistency check
    int totaltime = post_timing_f{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    //////////////////////////////////////////////////////////////////////
    // standard parameters for fine pointing
    int loadlength = post_timing_f{1}{2};
    int n_per_on = post_timing_f{1}{4};
    int n_load_on = post_timing_f{1}{5};
    bool end_load_on = post_timing_f{1}{6};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    //////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FSwitchNoRef_commanding(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_per_on,n_load_on,end_load_on,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SingleChop_deadtimes("fs",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_per_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = FSwitchNoRef_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_per_on * (n_load_on + 1),tscan,tdead);
    // Evaluate performance
    SingleChopNoRef_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_per_on * (n_load_on + 1),true,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// LCU configuration AT START-UP into NOMINAL mode, procedure
// This version assumes cold FPU but warm LO without attenuators
// It ensures the right frequency is picked up for a given band
procedure LCU_switchon_proc_aot {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; // LO frequency in GHz
}{
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlo = "name_configlo_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] result_d = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,0.0);
    double gate1_v = result_d[0];
    double gate2_v = result_d[1];
    double drain1_v = result_d[2];
    double drain2_v = result_d[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["switch_on_delay","config_lo_delay"],band,lo_freq);
    int switch_on_delay = iround(result[0]{0});
    int config_lo_delay = iround(result[1]{0});
    //
    result_d = CalibrationReader("name_lcu_safe_values",["d2_v"],band,0.0);
    drain2_v = result_d[0];
    //
    //Recovey from potential failure mode
    Set_LO_Nominal_block_aot();
    //
    //Send command: expect that we have already switched to NOMINAL
    //We set D2 to best guess and wait some time to stabilize chain temperature
    HIFI_Configure_LCU_block_aot(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,switch_on_delay);
    //
    //TM page dump and error flag clearance now contained in the above block
    //Set heater to their switch-on value
    HL_heater_block_aot(band,"nominal");
}

//////////////////////////////////////////////////////////////////////////
// Procedure to generate the telescope command for the DBS cross observing mode
// 
// As I have to set up the nodding pattern by hand, the cross must be
// defined in instrument coordinates - implies further restrictions
//
{int,int,int,string,int,double,double,bool,double,double,double,double[],double[],int[],double,double,int,int,int,int,int,int} procedure DBSCross_telescope {
    int naifid = 0; // Tracing object ID
    {double,double} mapcenter = {0.0,0.0}; // Coordinates of the center of the map
    double stepsize = 0.0050; // Distance between subsequent points in the raster line
    int npoints = 10; // Number of horizontal points
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    string throw = ""; // Identifier for chop throw, empty is standard
    {int,int,int,int,int,int,int,int,int,int,int,int,int} timing = {4,10,4,21,1,1800,0,10,1,1,1,50,0}; // full timing parameter list  
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF pointing cycles
}{
    // Assign values
    int pointing = timing{1};
    int loadlength = timing{3};
    int holdlength = timing{4};
    int n_loadinterval = timing{7};
    int n_pointsperscan = timing{10};
    int initlength = timing{11};
    int dangling = timing{12};
    // Create variables for telescope command
    string ib = GetBoresight(band,lo_freq,true);
    // A change of ra-dec depending on naifid may be needed
    double ra = mapcenter{0};
    double dec = mapcenter{1};
    // Pattern angle and throw of the chopper direction
    // The nodding angle should always be parallel to the chopper
    double[] chopper = GetSkyChopThrow(band,lo_freq,throw);
    double nodlength = chopper[0];
    double pattnod = chopper[1];
    nodlength = max(nodlength * 3600.0,2.0);
    // Map in instrument coordinates here to allow addition
    // (nod is always in instrument coordinates by default)
    bool fixed = false;
    double patt = pattnod;
    // Map parameters
    double d1 = stepsize * 3600.0;
    double d2 = d1;
    // Create first array of relative coordinates
    double[] xoff = [];
    double[] yoff = [];
    double x0 = -double(npoints - 1) / 2.0 * d1;
    double y0 = -double(npoints - 1) / 2.0 * d2;
    for(int i1 = 0 .. npoints - 1) {
        xoff[i1] = x0 + double(i1) * d1;
        yoff[i1] = 0.0;
    }
    // Currently the center point is observed twice - this may change
    for(int i2 = 0 .. npoints - 1) {
        xoff[i2 + npoints] = 0.0;
        yoff[i2 + npoints] = y0 + double(i2) * d2;
    }
    int numscans = length(xoff) / n_pointsperscan;
    // Initialization
    int icount = 0;
    int ioff = 0;
    int bphase = 0;
    double[] yarr = [];
    double[] zarr = [];
    int[] tp = [];
    // Now turn into array of pointings to be used
    if(n_pointsperscan > 1) {
        // Nodding OF raster
        int knod = 0;
        int nnod = 1;
        for(int i_cycle = 0 .. n_cycles - 1) {
            for(int i_scan = 0 .. numscans - 1) {
                for(int phasecount = 0 .. 1) {
                    bphase = (bphase + phasecount) % 2;
                    for(int i_point = 0 .. n_pointsperscan - 1) {
                        // Go to second nod only in B phases
                        zarr[icount] = xoff[ioff] + double(bphase) * nodlength;
                        yarr[icount] = yoff[ioff];
                        tp[icount] = pointing;
                        icount = icount + 1;
                        ioff = ioff + 1;
                    }
                    // Get points the second time in second phase
                    ioff = ioff + (phasecount - 1) * n_pointsperscan;
                }
            }
            // End of map
            ioff = 0;
        }
        // Consistency check
        if(length(yarr) != 4 * npoints * n_cycles) {
            CError("Custom map point number does not cover requested cross.");
        }
        // Treat all load slews as holds
        int nload = 0;
        int nhold = 2 * n_loadinterval * n_pointsperscan;
        // no hold if period too long
        if(nhold > 4 * npoints * n_cycles) {
            nhold = 0;
        }
    } else {
        // Nodding IN raster
        knod = 1;
        nnod = n_cycles;
        for(int ipoint2 = 0 .. numscans - 1) {
            zarr[ipoint2] = xoff[ipoint2];
            yarr[ipoint2] = yoff[ipoint2];
            tp[ipoint2] = pointing;
        }
        // Treat load slew either as load or as hold depending on n_cycles
        if(n_loadinterval > n_cycles) {
            nload = 0;
            nhold = n_loadinterval / n_cycles;
            // no hold if period too long
            if(nhold > numscans) {
                nhold = 0;
            }
        } else {
            nload = n_loadinterval;
            nhold = 0;
        }
    }
    // Check parameter compatibility with pointing command for parameters
    // which are no direct input parameters
    if(pointing < 10) {
        SError("Pointing phase length too short. Increase the number of integrations.");
    }
    if(length(yarr) > 3000) {
        IError("Map too large for cross mode. Reduce the number of points.");
    }
    if(nodlength > 960.0) {
        IError("Nodding length too long. Choose a smaller chop throw.");
    }
    // repetition at multiple frequencies not yet implemented:
    int trep = 0;
    int n_repeat = 0;
    // return parameters in required order

    return {initlength,0,dangling,ib,naifid,ra,dec,fixed,patt,0.0,0.0,yarr,zarr,tp,pattnod,nodlength,nnod,knod,loadlength,nload,holdlength,nhold};
}

//////////////////////////////////////////////////////////////////////////////
// routines needed for IST, but not part of observing modes
//////////////////////////////////////////////////////////////////////////////
//Set HIFI to standby II - laser status handled by configwbs.config
//It will switch off LO and let in into stanby. Lasers and HBB kept ON
obs HifiEngSetIntoStandby_II {
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(HifiIntoStandby_II());
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // ON integration
            HifiIntoStandby_II();
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//
// Magnet current scan, slow, block
// IF power as function of magnet current
block Magnet_scan_slow_fm HIFI 3271 {
    string band = "1a"; // HIFI band
    double magnet_current_min_h = -15.0; //minimum magnet current H
    double magnet_current_max_h = 10.0; //maximum magnet current H
    double magnet_current_min_v = -15.0; //minimum magnet current V
    double magnet_current_max_v = 10.0; //maximum magnet current V
    int n_steps = 100; //number of steps
    int integ_time = 4; //Total integration time in sec.: at least 2sec !  
    double lo_freq = 522.0; //LO frequency
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    int tune_target_magnet = 40 in [10,85]; //Target WBS illumination percentage during magnet tuning
    double shapiro_bias = 1.8; //Shapiro Mixer bias, same used for both polarization 
}{
    Start_block();
    {double,string}[] result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
    double magnetcurrent_max_h = result[0]{0};
    double magnetcurrent_max_v = result[1]{0};
    //We use special biasing to evidence the minima in the magnet scan
    result = ConfigurationReader("name_confilmix",["bias4magn_h","bias4magn_v"],band,lo_freq);
    double bias_h = shapiro_bias;
    //result[0]{0};
    double bias_v = shapiro_bias;
    //result[1]{0};
    Mixerbias(bias_h,bias_v);
    //
    int steps = 0;
    int steps_done = 0;
    double step_duration = 0.1;
    int steps_wanted = n_steps;
    if(steps_wanted < 1) {
        steps_wanted = 1;
    }
    double magnet_current_h = 0.0;
    double stepsize_h = 0.0;
    double magnet_current_v = 0.0;
    double stepsize_v = 0.0;
    if(steps_wanted > 1) {
        stepsize_h = (magnet_current_max_h - magnet_current_min_h) / (double(steps_wanted) - 1.0);
        stepsize_v = (magnet_current_max_v - magnet_current_min_v) / (double(steps_wanted) - 1.0);
    }
    //
    //Set magnet to maximum to avoid hysteresis
    Set_Magnet_current_proc_fm(magnetcurrent_max_h,magnetcurrent_max_v);
    //For band5, wait another 5 sec here
    if(band == "5a" || band == "5b") {
        delay(5);
    }
    //
    //Set magnets to starting value to do backend tuning
    Set_Magnet_current_proc_fm(magnet_current_max_h,magnet_current_max_v);
    //For band5, wait another 10 sec here
    if(band == "5a" || band == "5b") {
        delay(10);
    }
    //
    if(backend == "both" || backend == "wbs") {
        Hifi_HIFI_Tune_WBS($BBID,tune_target_magnet);
        //Get delay
        result = ConfigurationReader("name_delays",["wbs_tune_delay"],band,0.0);
        delay(iround(result[0]{0}));
        //
    }
    if(backend == "both" || backend == "hrs") {
        Hifi_HIFI_Tune_HRS($BBID);
        //Get delay
        result = ConfigurationReader("name_delays",["hrs_tune_delay"],band,0.0);
        delay(iround(result[0]{0}));
        //
    }
    //
    //Start scan: from max. to min. magnet downward.
    while(steps_done < steps_wanted) {
        steps = steps_wanted - steps_done;
        if(steps > n_steps) {
            steps = n_steps;
        }
        magnet_current_h = magnet_current_max_h - double(steps_done) * stepsize_h;
        magnet_current_v = magnet_current_max_v - double(steps_done) * stepsize_v;
        Set_Magnet_current_proc_fm(magnet_current_h,magnet_current_v);
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
        steps_done = steps_done + 1;
    }
}

// WBS attenuator tuning specific for spurious tests, procedure
// Both polarizations are treated
procedure WBS_tune_spurious_proc_fm {
    string band = "1a"; // HIFI band
}{
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["tune_target_spurious"],band,0.0);
    int tune_target_spurious = iround(result_d[0]{0});
    //
    //Now tune attenuators.
    WBS_tune_block_fm(band,tune_target_spurious);
    //
}

// Third part of WBS FM functional test, block
// Check effect of attenuators for laser 1
block FT_WBS_att_fm HIFI 3701 {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //
    //Set zero On
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_ON");
    delay(1);
    //
    //Initial configuration: overall attenuator set to max, indiv. to min.
    //H-Polarization
    //
    {double,string}[] result = ConfigurationReader("name_configwbs",["hwh_heater","hwh_latchup_s","hwh_att_in"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result[0]{0});
    string hwh_latchup_s = result[1]{1};
    int hwh_att_band4 = 0;
    int hwh_att_band3 = 0;
    int hwh_att_band2 = 0;
    int hwh_att_band1 = 0;
    int hwh_att_in = iround(result[2]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwv_heater","hwv_latchup_s","hwv_att_in"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result[0]{0});
    string hwv_latchup_s = result[1]{1};
    int hwv_att_band4 = 0;
    int hwv_att_band3 = 0;
    int hwv_att_band2 = 0;
    int hwv_att_band1 = 0;
    int hwv_att_in = iround(result[2]{0});
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    //Wait delay to allow all setting to be configured
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //Perform first COMB
    //
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_ON");
    delay(1);
    //
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //
    //Change attenuators: main att. -2dB while
    //subband attenuator +2dB: result should be unchanged
    int att_change = 2;
    hwh_att_band4 = att_change;
    hwh_att_band3 = att_change;
    hwh_att_band2 = att_change;
    hwh_att_band1 = att_change;
    hwh_att_in = hwh_att_in - att_change;
    hwv_att_band4 = att_change;
    hwv_att_band3 = att_change;
    hwv_att_band2 = att_change;
    hwv_att_band1 = att_change;
    hwv_att_in = hwv_att_in - att_change;
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    //Wait delay to allow all setting to be configured
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
    //Perform second COMB
    //
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //
    //Switch off zero and comb
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_OFF");
    delay(1);
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_OFF");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_OFF");
    delay(1);
    //Set att. to max.
    WBS_config_proc_max_att_w_laser_fm(band,laser_H,laser_V);
    //
}

// WBS latchup configuration, block
block WBS_set_Latchup_block_fm HIFI 3697 {
    string band = "1a"; // HIFI band
    string latchup_mode = "low" in ["high","low"]; //latchup level: level1 = low, level2 = high
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON: Laser1 or Laser2
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON: Laser1 or Laser2
}{
    //Start_block(); 
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4_comb","hwh_att_band3_comb","hwh_att_band2_comb","hwh_att_band1_comb","hwh_att_in_comb"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = "Level1";
    //result_d[3]{1};
    if(latchup_mode == "high") {
        hwh_latchup_s = "Level2";
    }
    int hwh_att_band4 = iround(result_d[4]{0});
    int hwh_att_band3 = iround(result_d[5]{0});
    int hwh_att_band2 = iround(result_d[6]{0});
    int hwh_att_band1 = iround(result_d[7]{0});
    int hwh_att_in = iround(result_d[8]{0});
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4_comb","hwv_att_band3_comb","hwv_att_band2_comb","hwv_att_band1_comb","hwv_att_in_comb"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = "Level1";
    //result_d[3]{1};
    if(latchup_mode == "high") {
        hwv_latchup_s = "Level2";
    }
    int hwv_att_band4 = iround(result_d[4]{0});
    int hwv_att_band3 = iround(result_d[5]{0});
    int hwv_att_band2 = iround(result_d[6]{0});
    int hwv_att_band1 = iround(result_d[7]{0});
    int hwv_att_in = iround(result_d[8]{0});
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
}

// Mirror an angular direction
double procedure MirrorDirection {
    double angle = 0.0; // Original angle
}{
    double fullcircle = 360.0;

    return (angle + fullcircle * 0.5) % fullcircle;
}

//General script to read TM1, TM2,etc, block
block LCU_Read_TM_pages_block_fm HIFI 3668 {
}{
    //Get various TM pages. This will clear error flags too
    Hifi_HIFI_LCU_all_tuning_hk();
    delay(2);
    //
}

//Stopmode
procedure StopMode_Gascell {
}{
    {double,string}[] result = ConfigurationReader("name_lastobsid",["last_obsid_current"],"0",0.0);
    //These are ILT-EGSE commands, not ruled by the 2TC/sec.
    //HifiIltEgse_GAS_set_BB_ID(0);
    //HifiIltEgse_GAS_set_OBS_ID(iround(result[0]{0}));
    //delay(1);
}

////////////////////////////////////////
// Standing wave analysis, procedure
// This is like a radiometry: 4 spectra
procedure Standing_wave_fm {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    double[] lo_freq_input = [500.0,500.15,0.02]; //Start, end and step lo_freq for the LO scan
}{
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_config_block_fm(band);
        WBS_calib_fm(band);
        WBS_tune_stndwave_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration
    //1. Total power mode (i.e. stability not an issue): for bands 1-5
    //
    int[] res = [0,0];
    int total_time = 0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
        total_time = res[0] * res[1];
        //
        //2. for bands 6-7 use freq. switch, i.e. slow chop
    } else {
        //Configure spectrometers integration after tuning for chopmode
        res = Configure_Spectrometer_freq_switching_proc_fm(band,integ_time * 2,hrs_mode,backend);
        total_time = res[0] * res[1];
    }
    //
    //Loop on LO frequencies. It is assumed that the LO is tuned at the middle frequency of the scan
    double lo_freq_ref = (lo_freq_input[0] + lo_freq_input[1]) / 2.0;
    double lo_freq = lo_freq_input[0];
    //
    while(lo_freq <= lo_freq_input[1]) {
        //
        //1. Total power mode (i.e. stability not an issue): for bands 1-5
        //        if ((band != "6a") && (band != "6b") && (band != "7a") && (band != "7b")) {
        //Set synthesizer to new LO freq.
        LCU_config_nominal_proc_fm(band,lo_freq);
        //
        //First internal loads
        Hot_cold(band,hrs_mode,backend,res[0] * res[1],"tp",0,0);
        //Then external loads
        //Hot_cold_external(band,res[0]*res[1],backend);
        //          } else {
        //        //2. for bands 6-7 use freq. switch, i.e. slow chop      
        //          //FSW is done between lo_freq_ref and current lo_freq
        //	  //Tune to the two frequencies
        //  	  //FSW1
        //  	  LCU_config_nominal_FSW_proc_fm(band,lo_freq_ref,(lo_freq+lo_freq_ref)/2.);
        //  	  //Additional command to store into LCU
        //  	  Hifi_HIFI_HL_store_tm($BBID);
        //  	  delay(1);
        //  	  //
        //  	  //FSW2
        //  	  LCU_config_nominal_FSW_proc_fm(band,lo_freq,(lo_freq+lo_freq_ref)/2.);
        //  	  //Additional command to store into LCU
        //  	  Hifi_HIFI_HL_store_tm($BBID);
        //  	  delay(1);
        //          //
        //	  //Start FSW integration on HBB (contains rotation to load)
        //	  Hot_spectra_FSW_fm(band,total_time,backend);
        //	  //Start FSW integration on CBB (contains rotation to load)
        //	  Cold_spectra_FSW_fm(band,total_time,backend);
        //          }
        //
        //Increase lo_freq
        lo_freq = lo_freq + lo_freq_input[2];
    }
}

/////////////////////////////////////////////////////////////////
// Derived parameters
// Procedure used by the spectral scan sequencer to compute the
// maximum frequency group length
int procedure GetSpectralScanGroupLength {
    string band = "4a"; // HIFI band
    double lo_freq_low = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4; // Frequency scan redundancy
}{
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq_low,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // Compute group length
    double central_freq = 0.5 * (lo_freq_low + lo_freq_up);
    double nocaliblen = GetFNoCalibLength(band,central_freq);
    int grouplen = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);

    return grouplen;
}

/////////////////////////////////////////////////////////////////
// Spectral scan in load chop without OFF calibration
// 
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiSScanProcLoadChopNoRef {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_cycles = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - Load Chop noRef",{data_time,0,0,0,0,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = SScanLoadChopNoRef_pre_timing(band,lo_freq,lo_freq_up,redundancy,effResolution,hr1,hr2,wb1,wb2,data_time,n_cycles,n_freq_point,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,double,double,int} tpar = Fine_telescope(naifid,onPosition,band,reffreq,pre_timing{0});
    // Dummy call to spacecraft command
    int[] telescopetimes = basic_fine_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,bool,int,int},double,double} post_timing = SScanChopNoRef_post_timing(pre_timing{0},telescopetimes);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = Fine_telescope(naifid,onPosition,band,reffreq,post_timing{1});
    // Call telescope command
    telescopetimes = basic_fine_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    // normal pre_timing values
    int loadlength = post_timing{1}{2};
    int n_per_on = post_timing{1}{4};
    int n_load_on = post_timing{1}{5};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        SScanLoadChopNoRef_commanding(band,reffreq,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,n_per_on,n_load_on,groupnumber,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SingleChop_deadtimes("lchop",band,reffreq,hr1,hr2,wb1,wb2,data_time,n_per_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanChopNoRef_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,n_per_on * imax(n_load_on,1),false,tscan,tdead);
    // Evaluate performance
    SScanChopNoRef_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_per_on * imax(n_load_on,1),groupnumber * n_freq_point,false,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//HIFI-COP-2.1-IF-FBk1
obs HifiEng_IF_FBk_COP {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
}{
    //General parameters in use
    int integ_time = 604;
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //  
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(IF_FBk_COP_proc_ops(band,lo_freq,hrs_mode,integ_time,backend));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            IF_FBk_COP_proc_ops(band,lo_freq,hrs_mode,integ_time,backend);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// WBS configuration with laser choice, procedure
// Both polarizations are treated
procedure WBS_config_w_laser_and_att_proc_fm {
    string band = "1a"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
    int[] att_h = [7,7,7,7,15]; //User input att. for optimum level H-polar
    int[] att_v = [7,7,7,7,15]; //User input att. for optimum level V-polar
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4","hwh_att_band3","hwh_att_band2","hwh_att_band1","hwh_att_in"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = att_h[3];
    int hwh_att_band3 = att_h[2];
    int hwh_att_band2 = att_h[1];
    int hwh_att_band1 = att_h[0];
    int hwh_att_in = att_h[4];
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4","hwv_att_band3","hwv_att_band2","hwv_att_band1","hwv_att_in"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = att_v[3];
    int hwv_att_band3 = att_v[2];
    int hwv_att_band2 = att_v[1];
    int hwv_att_band1 = att_v[0];
    int hwv_att_in = att_v[4];
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
}

//////////////////////////////////////
// blocks
//////////////////////////////////////
//Upload of LCU safety table, block
block LcuSafetyTableUpload_ops HIFI 7900 {
    string section = "P" in ["P","R"];
    int start = 0; // first table entry to upload (count form zero)
    int count = 0; // maximum number of table lines to upload
}{
    //StartBlock_ops();
    //Check prime or redundant status
    //{double, string}[] result_d = ConfigurationReader("name_chopper",
    //	["prime_or_redundant"],"0",0.0);
    //string section = "P";
    //if (result_d[0]{1} == "redundant" ) {
    //  section = "R";
    //  }
    //
    string tab = "LcuSafetyTable_" + section + ".config";
    //mois_comment("Uploading LCU safety table " + tab);
    int total = imin(table_size(tab),start + count);
    int done = start;
    int totalline = total - done;
    mois_comment("The following set of " + iceil(double(totalline) / 25.0) + " TCs will use the Formal Parameter mechanism.");
    //mois_comment("A total of " + totalline + " lines will be uploaded in " + iceil(double(totalline)/25.) + " calls to the Hifi_HIFI_Configure_LCU_table TC");
    int[] allIndices = icolumn(tab,"tableindex");
    int[] allValues = icolumn(tab,"value");
    int[] index = [];
    int[] value = [];
    int next = 0;
    //while(done < total ) {
    while(done < total) {
        for(int i = 0 .. 24) {
            next = imin(done,total - 1);
            index[i] = allIndices[next];
            value[i] = allValues[next];
            done = done + 1;
        }
        Hifi_HIFI_Configure_LCU_table($BBID,index[0],value[0],index[1],value[1],index[2],value[2],index[3],value[3],index[4],value[4],index[5],value[5],index[6],value[6],index[7],value[7],index[8],value[8],index[9],value[9],index[10],value[10],index[11],value[11],index[12],value[12],index[13],value[13],index[14],value[14],index[15],value[15],index[16],value[16],index[17],value[17],index[18],value[18],index[19],value[19],index[20],value[20],index[21],value[21],index[22],value[22],index[23],value[23],index[24],value[24]);
        delay(1);
    }
}

//  LCU6Lb configuration into SAFE mode, procedure
procedure LCU6Lb_config_safe_proc_fm {
    string band = "6b"; // HIFI band
    double lo_freq = 1600.0 in [1575.0,1700.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

//General script to read TM1, TM2,etc, procedure
procedure LCU_Read_TM_pages_proc_fm {
}{
    //Get various TM pages. This will clear error flags too
    Hifi_HIFI_LCU_all_tuning_hk();
    delay(2);
}

//////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the observing mode
{double,double,double,double,double} procedure PositionSwitch_noisecomputer {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    int n_cycles = 1; // Number of map coverages
    double tscan = 60.0; // Total average duration of one scan
    double tdead = 10.0; // Average dead time in one slew
}{
    double inttime = (tscan - tdead) / 2.0;
    // Integration time per pointing phase
    // Get parameters which are needed
    double tsys = InterpolateTsys(band,lo_freq);
    double eta_mb = InterpolateCoupling(band,lo_freq);
    double[] gssb = InterpolateGssb(band,lo_freq);
    // Get the drift parameters to compute the drift noise
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double allan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // Get actual noise
    // This is returned twice: for both limiting resolutions
    double systemnoise_lores = TwoPhaseNoise(inttime / allan_time_lores,[tdead / allan_time_lores,alpha]);
    double systemnoise_hires = TwoPhaseNoise(inttime / allan_time_hires,[tdead / allan_time_hires,alpha]);
    double noiseratio = TwoPhaseNoiseRatio(inttime / allan_time_lores,[tdead / allan_time_lores,alpha]);
    // Compute total double sideband noise 
    double dsbnoise_lores = tsys * sqrt(systemnoise_lores / (eff_resolution{1} * 1000000.0 * double(n_cycles) * tscan));
    double dsbnoise_hires = tsys * sqrt(systemnoise_hires / (eff_resolution{0} * 1000000.0 * double(n_cycles) * tscan));
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Get single sideband noise equivalent
    double usbnoise_lores = dsbnoise_lores / gssb[0];
    double usbnoise_hires = dsbnoise_hires / gssb[0];
    double lsbnoise_lores = dsbnoise_lores / gssb[1];
    double lsbnoise_hires = dsbnoise_hires / gssb[1];
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiseratio};
}

//  LCU3a configuration and tuning, procedure
procedure LCU3a_config_tune_proc_fm {
    string band = "3a"; // HIFI band
    double lo_freq = 810.0 in [807.0,848.0]; //LO frequency
    double drain_2_factor = 100.0; //Percentage factor of the targetted drain voltage
}{
    error("This module is obsolete: use LO_tuning_block_fm  instead");
}

//HIFI-FCP-HC1: chopper health check#3
obs HifiEng_Chopper_FT3_COP {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Chopper_FT3_COP_proc_ops(prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Chopper_FT3_COP_proc_ops(prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//The blocks
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
///////////////////////////////////////////////////
//This block is obsolete. It remains here as
//a placeholder for the BBID use.
// Single integration with no change of setups,block
//block Total_power_integration_block_fm HIFI 3630 {
//  }{
// }
// Take total power spectra, block
block Spectro_total_power_block_fm HIFI 3606 {
    string band = "1a"; // HIFI band
    int[] timing_parms = [4,1]; //single readout time in sec. and n_wbs_start
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    int integ_time = timing_parms[0] * timing_parms[1];
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"tp",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// OBS SFT, block
block OBS_SFT_block_ops HIFI 7926 {
}{
    StartBlock_ops();
    //Check PM memory: this is for OBS5.4.0
    int check_start = 0x5500;
    int check_end = 0x17d0b;
    int check_crc = 0x31a0;
    mois_step("Check PM memory");
    Hifi_HIFI_check_PM_memory(check_start,check_end,check_crc);
    delay(3);
    mois_tmcheck("No error packet should have been generated");
    //
    //Set Housekeeping rate to 1/sec
    mois_step("Set HK rate to 1/sec");
    string hk_rate = "1_pkt_per_s";
    Hifi_HIFI_Housekeeping_on("1_pkt_per_s","ON","ON","ON","ON","ON","ON");
    delay(1);
    mois_tmcheck("Verify that HIFI telemetry packets (3,25,1025) - HIFI_PERIODIC_HK - are arriving every 1 second.");
    //
    mois_step("Run HIFI_enable_time_verify");
    Hifi_HIFI_enable_time_verify();
    delay(1);
    //Simulate science: are the spectrometers automatically configured ?
    mois_step("Simulate spectroscopy measurement");
    Hifi_HIFI_simulate_science();
    delay(30);
    mois_tmcheck("Verify that HIFI telemetry packets (21,1) are coming in.");
    //Should abort the above
    mois_step("Abort spectroscopy measurement started previously");
    Hifi_HIFI_abort_spectroscopy();
    delay(1);
    mois_tmcheck("Verify that HIFI telemetry packets (21,1) are not arriving anymore");
}

// upload of memory patch table, block
//Prime/Redundant is handled with the CUS table
block LcuMemoryPatchUpload_ops HIFI 7902 {
    string section = "P" in ["P","R"];
}{
    StartBlock_ops();
    //
    //{int, int[]}[] runs = LcuGetMemoryRuns_ops( section);
    {int,int[]}[] runs = LcuGetMemoryRuns(section,1);
    int runcount = length(runs);
    if(runcount > 50) {
        error("LCU memory patch has more than 50 lines. This will not fit in the procedure.");
    }
    if(runcount != 0) {
        mois_comment("Upload of EFFECTIVE patch will be complete in " + runcount + " Hifi_HIFI_load_LCU TC call(s)");
    } else {
        mois_comment("No patch uploaded because memory patch file is empty");
    }
    for(int i = 0 .. runcount - 1) {
        {int}[] par = [];
        int[] values = runs[i]{1};
        int count = length(values);
        for(int j = 0 .. count - 1) {
            par[j] = {values[j]};
        }
        int crc = checksum("short",values);
        Hifi_HIFI_load_LCU(runs[i]{0},count,par,crc);
        delay(2);
    }
    //Complement the number of TCs sent to reach the fixed TC pattern needed for TPF
    if(runcount != 0) {
        int nb_TC_needed = 50;
        //Foresee as much as possible
        int remaining_TC = nb_TC_needed - runcount;
        mois_comment("The following " + remaining_TC + " TCs are dummy repetition of the first patch line");
        //Compute parameters for constant inputs
        values = runs[0]{1};
        count = length(values);
        for(int jj = 0 .. count - 1) {
            par[jj] = {values[jj]};
        }
        crc = checksum("short",values);
        for(int ii = 1 .. remaining_TC) {
            Hifi_HIFI_load_LCU(runs[0]{0},count,par,crc);
            delay(2);
        }
    } else {
        //empty patch
    }
    //
}

//HIFI vector scan, block for experts: allow all vector scan parameters as user input
//Check vector scan with some default parameters
block Vector_scan_EXPERT_w_M1_block_fm HIFI 3771 {
    string band = "7b" in ["7b","7b"]; // HIFI band
    double lo_freq = 1890.0; //LO frequency
    double step_drain2_v = 0.05; //D2_V steps during vector scan
    int nsteps = 10; //Number of steps. Should not be larger than 10
    double step_time = 1.0; //In seconds.
    double drain2_v_start = 1.5; //Starting D2_V in vector scan
    double m1 = -7.0; //M1 multiplier voltage
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = m1;
    //result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    //double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlcu,["drain2_v"],band,lo_freq);
    double drain2_safe = result[0]{0};
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    //double step_drain2_v = result[0]{0};
    //int nsteps = iround(result[1]{0});
    //double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    //delay(1);
    //Execute vector scan 
    Hifi_HIFI_vector_scan($BBID);
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

// procedure called to get the instrument into standby
// with WBS lasers Off and HBB ON
procedure HifiIntoStandby_I {
}{
    //FPU stand-by with HBB On
    Init_MSA_aot("0","CLOSE",0.0,true,"ON");
    //WBS stand-by with laser OFF
    WBS_standby_block_aot("OFF");
    //HRS should already have max att. and locked LO 
    //done during the power-on., or via StandbyII
}

//LO enable in manual commanding
mode HifiManCmd_LO_enable {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    mois_comment("Procedure to enable the LOU S/S");
    StartMode_block_ops();
    //
    mois_step("Enable LOU");
    LCU_enable_all_bands_block_fm();
    //
    StopMode_block_ops();
    // -> to issue last obsd/bbid
}

// HIFI goto SAFE, block
//
block HIFI_goto_SAFE_block_fm HIFI 3920 {
}{
    Start_block();
    Hifi_HIFI_goto_safe();
    {double,string}[] result = ConfigurationReader("name_delays",["stdby_delay","wbs_config_delay","hrs_config_delay","config_fpu_delay"],"0",0.0);
    delay(iround(result[0]{0} + result[1]{0} + result[2]{0} + result[3]{0}));
}

//  LCU configuration with no retune, block
//  Uses best guess D2 voltage from configlcu table
block LCU_config_nominal_noretune_block_fm HIFI 3614 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    double lo_freq_ref = 500.0; //LO frequency
}{
    //Fetch LO parameters
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //Get index of frequency used to get D2_v
    {double,string}[] result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq_ref);
    int freq_nx_ref = ifloor(result[0]{0});
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Check frequency indices don't differ by more than 1
    if(abs(double(freq_nx) - double(freq_nx_ref)) > 1.0) {
        error("The command HIFI_Conf_f_LCU_noretune is used with frequencies whose indices differ by more than 1 (" + lo_freq + " GHz and " + lo_freq_ref + " GHz).");
    }
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //
    //Use accurate AOT delay for LO tuning
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq_ref);
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq_ref);
    double v_d2 = result[0]{0};
    double drain2_max = min(v_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double[] cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq_ref);
    double drain2_safe = cresult[0];
    result = ConfigurationReader("name_delays",["lock_lo_delay","vd2_rampup_speed"],band,lo_freq);
    int config_lo_delay = iceil(result[0]{0} + (drain2_max - drain2_safe) / result[1]{0});
    //Send command
    Hifi_HIFI_Conf_f_LCU_noretune($BBID,freq_nx,lsu_main,lsu_offset);
    //
    delay(config_lo_delay);
    message(config_lo_delay);
}

//  LCU1a configuration into SAFE mode, procedure
procedure LCU1a_config_safe_proc_fm {
    string band = "1a"; // HIFI band
    double lo_freq = 500.0 in [488.0,552.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

//////////////////////////////////////////////////////////////////////////
// Procedure to generate the telescope command for the DBS raster observing mode
{int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double,int,int,int,double,double,int,int,int,int} procedure DBSRaster_telescope {
    int naifid = 0; // Tracing object ID
    {double,double} mapcenter = {0.0,0.0}; // Coordinates of the center of the map
    {double,double} linedistance = {0.0050,0.0050}; // Distance between subsequent rows
    double stepsize = 0.0050; // Distance between subsequent points in the raster line
    int nlines_tot = 1; // Number of rows in the map;
    int npoints = 10; // Number of points per row 
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    string throw = ""; // Identifier for chop throw, empty is standard
    {int,int,int,int,int,int,int,int,int,int,int,int,int} timing = {4,10,4,21,1,1800,0,10,1,1,1,50,0}; // full timing parameter list  
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF pointing cycles
}{
    // Assign values
    int pointing = timing{1};
    int loadlength = timing{3};
    int holdlength = timing{4};
    int n_loadinterval = timing{7};
    int initlength = timing{11};
    int dangling = timing{12};
    // Create variables for telescope command
    string ib = GetBoresight(band,lo_freq,true);
    // A change of ra-dec depending on naifid may be needed
    double ra = mapcenter{0};
    double dec = mapcenter{1};
    double patt = AngleFromVector(linedistance);
    patt = RotateRight(patt);
    // Pattern angle and throw of the chopper direction
    // The nodding angle should always be parallel to the chopper
    double[] chopper = GetSkyChopThrow(band,lo_freq,throw);
    double nodlength = chopper[0];
    double pattnod = chopper[1];
    nodlength = max(nodlength * 3600.0,2.0);
    // Map always in sky coordinates, 
    // (nod is always in instrument coordinates by default)
    bool fixed = true;
    // Map parameters
    double rowstep = 0.5 / 3600.0;
    double d1 = double(iceil(stepsize / rowstep)) * rowstep * 3600.0;
    double linestep = 0.5 / 3600.0;
    double d2 = AngleVectorLength(linedistance);
    d2 = double(iceil(d2 / linestep)) * linestep * 3600.0;
    // Exception for the "impossible" case of spacings below 2arcsec
    d1 = max(d1,2.0);
    d2 = max(d2,2.0);
    // Treat load slew either as load or as hold depending on n_cycles
    if(n_loadinterval > n_cycles) {
        int nload = 0;
        int nhold = n_loadinterval / n_cycles;
        // no hold if period too long
        if(nhold > npoints * nlines_tot) {
            nhold = 0;
        }
    } else {
        nload = n_loadinterval;
        nhold = 0;
    }
    // Check parameter compatibility with pointing command for parameters
    // which are no direct input parameters
    if(pointing < 10) {
        SError("Pointing phase length too short. Increase the number of integrations.");
    }
    if(nodlength > 960.0) {
        IError("Nodding length too long. Choose a smaller chop throw.");
    }
    if(d1 > 480.0) {
        IError("Raster point spacing too coarse. Increase the sampling.");
    }
    if(d2 > 480.0) {
        IError("Raster line spacing too coarse. Increase the sampling.");
    }
    // repetition at multiple frequencies not yet implemented:
    int trep = 0;
    int n_repeat = 1;
    // parameters for OFF position - not used
    int koff = 0;
    int toff = 0;
    double raoff = 0.0;
    double decoff = 0.0;
    // return parameters in required order

    return {initlength,0,dangling,ib,naifid,ra,dec,fixed,patt,0.0,0.0,npoints,nlines_tot,d1,d2,pointing,holdlength,nhold,pattnod,nodlength,n_cycles,koff,toff,raoff,decoff,n_repeat,trep,loadlength,nload};
}

// WBS attenuator tuning specific for spurious tests, procedure
// Both polarizations are treated
procedure WBS_tune_stndwave_proc_fm {
    string band = "1a"; // HIFI band
}{
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["tune_target_spurious"],band,0.0);
    int tune_target_spurious = iround(result_d[0]{0});
    //
    //Now tune attenuators.
    WBS_tune_block_fm(band,tune_target_spurious);
    //
}

/////////////////////////////////////////////////////////
// WBS configuration with maximum attenuation, block
// Laser can be chosen
block WBS_config_max_att_w_laser_block_fm HIFI 3641 {
    string band = "1a"; // HIFI band
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
}{
    //Start_block();
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = 7;
    int hwh_att_band3 = 7;
    int hwh_att_band2 = 7;
    int hwh_att_band1 = 7;
    int hwh_att_in = 15;
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //delay(wbs_config_delay);
    //V-Polarization
    //Get configuration parameters
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = 7;
    int hwv_att_band3 = 7;
    int hwv_att_band2 = 7;
    int hwv_att_band1 = 7;
    int hwv_att_in = 15;
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    //Wait delay to allow all setting to be configured
    delay(wbs_config_delay);
}

////////////////////////////////////
// OTF observing mode
// 
// Return time and noise levels
{string,double,double}[] procedure HifiMappingProcOTFSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints = 10 in [1,720]; // Number of data dumps per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,5]; // chunk size given by the data rates and optimum speed
    int n_int_on = 1 in [1,1800]; // Supersamplingfactor
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // Compute derived quantities
    int main_phase = iceil(0.3 * allan_time_lores);
    // How many lines could we do at most using datalimit?
    int n_linesperscan_guess = main_phase / datalimit + 1;
    n_linesperscan_guess = imax(n_linesperscan_guess * n_linesperscan_guess / npoints,1);
    // restrict the scan size
    if(nlines == 1 && n_linesperscan_guess > 1) {
        n_linesperscan_guess = 2;
    } else {
        n_linesperscan_guess = IMultiple(n_linesperscan_guess,nlines);
        n_linesperscan_guess = imin(n_linesperscan_guess,nlines);
    }
    int n_linesperscan_range = 1 - n_linesperscan_guess;
    if(n_linesperscan_range == 0) {
        n_linesperscan_range = 1;
    }
    double n_pointsperscan = double(n_linesperscan * npoints);
    // Compute back
    int int_time_guess = imax(main_phase / iceil(sqrt(n_pointsperscan)),datalimit);
    int data_time_guess = imin(5,int_time_guess);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_int_on_guess = imax(int_time_guess / data_time_guess,1);
    int n_int_on_range = 1 - n_int_on_guess;
    if(n_int_on_range == 0) {
        n_int_on_range = 1;
    }
    // OFF integration
    int n_switch_off_guess = ifloor(double(n_int_on) * 0.67 * sqrt(n_pointsperscan));
    int n_switch_off_range = n_switch_off_guess / 3;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_int_on",double(n_int_on_guess),double(n_int_on_range)},{"n_linesperscan",double(n_linesperscan_guess),double(n_linesperscan_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)}];

    return retvalues;
}

// Interpolate differential load chop Allan time and exponent
double[] procedure InterpolateSpecLChopAllan {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    bool subband = false; // 1GHz bandwith reference instead of full IF
}{
    // subband is not used yet
    double[] allan = CalibrationReader("loadchop_Allan",["spec_Allan_time","spec_Allan_exp","spec_binning_exp"],band,lo_freq);

    return allan;
}

/////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing for a
// Spectral Scan DBS observing mode
// 
// We currently assume that each nodding motion is related to an
// instrument calibration. This may be an efficiency limitation if
// more calibration measurements are needed. Then the loop sequence
// should be changed.
// 
// This implementation assumes that the whole scan can be performed
// with a single pointing command. If the system temperature varies
// too much so that it cannot be compensated by a slight change of
// the redundancy, the scan has to be split into several calls of this
// mode.
//
{{int,int,int,int,int,int,int,int,int,bool,int,int,int},{int,double,double[],int[][],bool,double[],int,bool}} procedure SScanDBS_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq_low = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4; // Frequency scan redundancy
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_chop = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Create composite readout structure for backends
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First check the group length 
    // The frequency group length is given by n_freq_point.
    // It is derived in the sequencer using 
    //            GetFNoCalibLength(band,ref_freq);
    // For n_cycles>1 it has to be unity, everything else is rejected
    // We rely on the sequencer to determine the best group length
    if(n_cycles > 1 && n_freq_point > 1) {
        SError("Only frequency group length 1 allowed for cycle numbers > 1.");
    }
    // Get frequency grid characteristic parameters
    {int,double,double[],int[][],int,bool} fqparms = MakeFreqGrid(band,lo_freq_low,lo_freq_up,redundancy,0.0,n_freq_point);
    double reffreq = fqparms{1};
    double[] freqgrid = fqparms{2};
    int[][] grouporder = fqparms{3};
    // Process tuning level grid
    double[][] levelgrid = GetSScanLevelGrid(band,wbs1,wbs2,freqgrid,fqparms{0},grouporder);
    {bool,double[]} targets = TargetLevels(band,reffreq,levelgrid);
    bool retuning = targets{0};
    double[] targetgrid = targets{1};
    string reftarget = "";
    if(retuning) {
        reftarget = "sscan_normal";
    }
    // Collect all frequency information in a tuple
    {int,double,double[],int[][],bool,double[],int,bool} spectralparms = {fqparms{0},reffreq,freqgrid,grouporder,retuning,targetgrid,fqparms{4},fqparms{5}};
    //////////////////////////////////////////////////////////////////////
    // Get timing within the normal DBS observations
    // Compute load integration time
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,reffreq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    int jitterdead = GetMaxTimeJitter(band,reffreq);
    // Integration time per frequency and pointing
    int inttime = 2 * n_chop * data_time;
    int readouttime = data_time;
    // Duration of initial set up
    // Staying at the same frequency makes no sense here. 
    // First frequency point
    double runningfreq = freqgrid[grouporder[0][0]];
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,runningfreq,hrs1,hrs2,wbs1{0},wbs2{0},"sscan_normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,runningfreq,false);
    }
    initlength = initlength + loadlength;
    // Tuning delays
    int bigtunestep = duration(HIFIRetuneFreq(band,reffreq,reftarget));
    // Correct for variation within the band
    int tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq);
    bigtunestep = bigtunestep + tunediff;
    if(n_freq_point > 1) {
        int smallstep = duration(HIFIChangeFreq(band,reffreq));
    } else {
        smallstep = bigtunestep;
    }
    // For double phases I can use the added jitterdead in both phases for tune
    int halftunestep = (bigtunestep - jitterdead + 1) / 2;
    // Check load_interval allowance
    int scan_time = 2 * inttime + bigtunestep;
    if(scan_time > load_spacing) {
        SError("Load interval of " + load_interval + "s is exceeded by " + n_chop + " chop cycles.");
    }
    // Rough estimate of the pointing time to issue a representative 
    // telescope command
    if(n_cycles > 1) {
        // How often do I have to perform a load slew
        int n_loadinterval = imax(load_interval / scan_time,1);
        // fit with n_cycles
        n_loadinterval = imin(n_loadinterval,n_cycles);
        n_loadinterval = IMultiple(n_loadinterval,n_cycles);
        // Pointing time
        int pointing = inttime + jitterdead;
    } else {
        n_loadinterval = 1;
        pointing = n_freq_point * inttime + (n_freq_point - 1) * smallstep + halftunestep + jitterdead;
    }
    int n_bchop = n_chop;
    // recompute load length during slews in case of short integrations
    // This regime must be maintained in the post_timing
    if(n_loadinterval <= 1) {
        loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,false,eff_resolution{0},data_time,backendreadoutparms));
        loadlength = loadlength + readoutdead;
    }
    // No dangling needed in this mode - we stop halftunelength before telescope
    int dangling = 0;
    bool end_load = false;
    // Return all the times needed for telescope call and post_timing processing

    return {{inttime,pointing,readouttime,loadlength,jitterdead,load_spacing,bigtunestep,n_loadinterval,n_bchop,end_load,smallstep,initlength,dangling},spectralparms};
}

/////////////////////////////////////////////////////////////////
// Fast-chop spectral scan observing modes
// 
{string,double,double}[] procedure HifiSScanProcFastDBSSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time / 2);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hr1{0},hr1{1},hr1{3}},{hr2{0},hr2{1},hr2{3}},wb1,wb2};
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    // Now general part of DBS modes
    // Get the drift parameters to compute the drift noise
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {double,double} phaselengths = DBSPhaseLengths(band,reffreq,effResolution,continuumDetection,narrowReference);
    // Compute derived quantities
    // Top down approach here
    int main_phase = iceil(phaselengths{0});
    // Arbitrary selection of data_time
    int data_time_guess = 20;
    // remaining part for n_switch
    int n_switch_on_guess = main_phase / (n_freq_point_guess * data_time_guess) + 1;
    data_time_guess = main_phase / (n_freq_point_guess * n_switch_on_guess);
    // Check with data rate
    {int,double[]} dataparms = DataTaking(backendreadoutparms,8);
    int datalimit = 2 * dataparms{0};
    if(data_time_guess < datalimit) {
        data_time_guess = datalimit;
        n_switch_on_guess = 1;
    }
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // Chop phase length
    double phase_min = min(max(phaselengths{1},0.15),1.5);
    int n_int_on_guess = ifloor(double(data_time_guess) / (2.0 * phase_min));
    int n_int_on_range = -n_int_on_guess / 2;
    if(n_int_on_range == 0) {
        n_int_on_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_int_on",double(n_int_on_guess),double(n_int_on_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)}];

    return retvalues;
}

// FPU Standby with HBB On, block
block Band0_hbb_on_fm HIFI 3298 {
    string band = "0"; // HIFI band
    string chop_loop = "CLOSE"; // Chopper Loop status
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current_on"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    result_d = ConfigurationReader("name_confilfpu",["bias_standby_h","diplexer_standby_h","bias_standby_v","diplexer_standby_v","diplex_h_ctrl_mode","diplex_v_ctrl_mode","chop_M3right"],band,0.0);
    //
    double bias_H = result_d[0]{0};
    double diplex_H = result_d[1]{0};
    double bias_V = result_d[2]{0};
    double diplex_V = result_d[3]{0};
    int diplex_h_ctrl_mode = iround(result_d[4]{0});
    int diplex_v_ctrl_mode = iround(result_d[5]{0});
    //
    //Retrieve magnets Magnet are so far at maximum value. Now set to nominal
    double magnetcurrent_H = result_d[1]{0};
    double magnetcurrent_V = result_d[4]{0};
    //
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_standby_h","magnet_standby_v"],band,0.0);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,0.0);
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
}

// Interpolate differential total power sky chop Allan time and exponent
double[] procedure InterpolateTpChopAllan {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    bool subband = false; // 1GHz bandwith reference instead of full IF
}{
    // subband is not used yet
    double[] allan = CalibrationReader("chop_Allan",["tp_Allan_time","tp_Allan_exp","tp_binning_exp"],band,lo_freq);

    return allan;
}

//Test CSS-IEGSE link during IST
block HIFI_CcsHanderTestBB HIFI 3698 {
    int cmdCnt = 1;
}{
    for(int k = 1 .. cmdCnt) {
        //IstCcsEgse_YC00X962(2,[{1},{2}]);
        delay(1);
    }
}

// Recalculate and verify LCU memory checksum
block LcuChecksumRecalc_fm HIFI 3904 {
}{
    Start_block();
    string section = GetLcuSection();
    int expected_sum = ilookup("LcuChecksumTable.config",section,"normal");
    // initial install of default safe table - simulate transition to normal
    Hifi_HIFI_LCU_Single($BBID,"HL_DEF_SAFE");
    delay(1);
    //Stop LCU HK collection - see SPR-1679
    //Get applicable HK rate
    {double,string}[] result_d = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    string hk_rate = result_d[0]{1};
    Hifi_HIFI_Housekeeping_on(hk_rate,"ON","OFF","ON","ON","ON","ON");
    delay(1);
    Hifi_HIFI_check_LCU_memory($BBID,3000,expected_sum);
    //add 2sec to the initial 4sec - SPR-1744
    delay(6);
    //Restore HK
    Hifi_HIFI_Housekeeping_on(hk_rate,"ON","ON","ON","ON","ON","ON");
    delay(1);
}

//HIFI-COP-3-FTP
obs HifiEng_FT_pumped_COP {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //General parameters in use
    int integ_time = 4;
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(FT_pumped_COP_proc_ops(band,integ_time,backend,hrs_mode));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            FT_pumped_COP_proc_ops(band,integ_time,backend,hrs_mode);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// Set the whole instrument to standby I mode
// This only switches the lasers off
// Will keep the HBB on
mode HifiManCmd_HIFI_standbyII_to_standbyI {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string laser_H = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2","Lasers_off"]; //WBS-V laser to be set ON
    string chopper_loop = "OPEN" in ["OPEN","CLOSE"]; //chopper loop status
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    Mode_status_check_standby_II(laser_H,laser_V,chopper_loop,"down",prime_or_redundant);
    mois_comment("Set HIFI to standby mode I with chopper loop " + chopper_loop);
    StartMode_block_ops();
    //WBS stand-by with lasers off
    mois_step("Switch WBS-H and WBS-V lasers OFF");
    WBS_standby_block_ops("0","Lasers_off","Lasers_off");
    //
    StopMode_block_ops();
    Mode_status_check_standby_I(chopper_loop,"up",prime_or_redundant);
}

// BLOCK : Functional Test No 2 (HRS Sine Internal Test)
block HRS_functional_test_No_2_Sine_block_fm HIFI 3620 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code for both polarizations
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //Fill in block parameter names for each mode - consequence of SPR-0198
    string[] hrs_blocks_sine_ultra = ["sine_ultra","sine_ultra","sine_ultra","sine_ultra","sine_ultra","sine_ultra","sine_ultra","sine_ultra"];
    string[] hrs_blocks_sine_wide = ["sine_wide","sine_wide","sine_wide","sine_wide","sine_wide","sine_wide","sine_wide","sine_wide"];
    string[] hrs_blocks_sine_low = ["sine_hilonom","low","sine_low","low_nominal","sine_low_nom","low","sine_low","high_nominal_low"];
    string[] hrs_blocks_sine_nom = ["sine_hilonom","high_nominal","high_nominal","low_nominal","sine_low_nom","high_nominal","high_nominal","high_nominal_low"];
    string[] hrs_blocks_sine_high = ["sine_hilonom","high_nominal","high_nominal","high","high","high_nominal","high_nominal","high_nominal_low"];
    // Configure spectroscopy
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    // Configure LO and attenuators
    //=============================
    HRS_config_att_lo_fm(band,hrs_mode);
    //
    // Loops on the different configurations of the HRS
    //======================================
    //Calls the 5 modes to be checked
    //sine_ultra
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_sine_ultra[0],hrs_blocks_sine_ultra[1],hrs_blocks_sine_ultra[2],hrs_blocks_sine_ultra[3],hrs_blocks_sine_ultra[4],hrs_blocks_sine_ultra[5],hrs_blocks_sine_ultra[6],hrs_blocks_sine_ultra[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_sine_ultra[0],hrs_blocks_sine_ultra[1],hrs_blocks_sine_ultra[2],hrs_blocks_sine_ultra[3],hrs_blocks_sine_ultra[4],hrs_blocks_sine_ultra[5],hrs_blocks_sine_ultra[6],hrs_blocks_sine_ultra[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //sine_wide
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_sine_wide[0],hrs_blocks_sine_wide[1],hrs_blocks_sine_wide[2],hrs_blocks_sine_wide[3],hrs_blocks_sine_wide[4],hrs_blocks_sine_wide[5],hrs_blocks_sine_wide[6],hrs_blocks_sine_wide[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_sine_wide[0],hrs_blocks_sine_wide[1],hrs_blocks_sine_wide[2],hrs_blocks_sine_wide[3],hrs_blocks_sine_wide[4],hrs_blocks_sine_wide[5],hrs_blocks_sine_wide[6],hrs_blocks_sine_wide[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //sine_low
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_sine_low[0],hrs_blocks_sine_low[1],hrs_blocks_sine_low[2],hrs_blocks_sine_low[3],hrs_blocks_sine_low[4],hrs_blocks_sine_low[5],hrs_blocks_sine_low[6],hrs_blocks_sine_low[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_sine_low[0],hrs_blocks_sine_low[1],hrs_blocks_sine_low[2],hrs_blocks_sine_low[3],hrs_blocks_sine_low[4],hrs_blocks_sine_low[5],hrs_blocks_sine_low[6],hrs_blocks_sine_low[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Sine_nominal
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_sine_nom[0],hrs_blocks_sine_nom[1],hrs_blocks_sine_nom[2],hrs_blocks_sine_nom[3],hrs_blocks_sine_nom[4],hrs_blocks_sine_nom[5],hrs_blocks_sine_nom[6],hrs_blocks_sine_nom[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_sine_nom[0],hrs_blocks_sine_nom[1],hrs_blocks_sine_nom[2],hrs_blocks_sine_nom[3],hrs_blocks_sine_nom[4],hrs_blocks_sine_nom[5],hrs_blocks_sine_nom[6],hrs_blocks_sine_nom[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
    //Sine_high
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrs_blocks_sine_high[0],hrs_blocks_sine_high[1],hrs_blocks_sine_high[2],hrs_blocks_sine_high[3],hrs_blocks_sine_high[4],hrs_blocks_sine_high[5],hrs_blocks_sine_high[6],hrs_blocks_sine_high[7]);
    //delay(1);
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrs_blocks_sine_high[0],hrs_blocks_sine_high[1],hrs_blocks_sine_high[2],hrs_blocks_sine_high[3],hrs_blocks_sine_high[4],hrs_blocks_sine_high[5],hrs_blocks_sine_high[6],hrs_blocks_sine_high[7]);
    delay(1);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
}

{int,double,double,double,double,double} obs HifiPointModeFastDBS {
    string modeName = "dbs";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Single Point - DBS fastChop",{data_time,0,n_switch_on,n_int_on,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,bool,int,int,int} pre_timing = FastDBS_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},bool,double,double} post_timing = DBS_post_timing(pre_timing,telescopetimes,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",post_timing{1},n_cycles);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    bool end_load = post_timing{1}{9};
    int shiftlength = post_timing{1}{10};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FastDBS_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,n_loadinterval,end_load,final_load,startobs,telescopetimes,loadlength,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastDBS_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBS_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,n_seq * n_int_on * (n_load + 1),tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//  LCU configuration AT START-UP into NOMINAL mode, procedure
//  Uses SFT approach with old 5 TM TC call
procedure LCU_switchon_proc_sft {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //Clear potential failure mode
    Set_LO_Nominal_block_fm();
    //
    //We use a constant frequency for each band, regardless of the input
    double lo_freq = 0.0;
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq","midfreq","keyfreqwarm","keyfreq_dummy"],band,0.0);
    lo_freq = result_d[0];
    //this is for cold operations
    //   lo_freq = result_d[2];   //this is for warm operations
    //   lo_freq = result_d[3];     //this is for dummy operations
    ////FM_CUS_11.5: replace keyfreq by the only allowed frequency for warm IST
    //For band 7b, 1723.5 may be problematic. Take mid freq. instead
    //if (band == "7b") {
    //  lo_freq = result_d[1];  
    //  }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_confindex = "name_confindex_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["switch_on_delay","config_lo_delay"],band,lo_freq);
    int switch_on_delay = iround(result[0]{0});
    int config_lo_delay = iround(result[1]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    drain2_v = cresult[0];
    //Send command: expect that we have already switched to NOMINAL
    //We set D2 to best guess and wait some time to stabilize chain temperature
    HIFI_Configure_LCU_block_sft(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,switch_on_delay);
    //
    //Set heater to their switch-on value
    HL_heater_block_fm(band,"nominal");
}

//  LCU configuration AT START-UP into NOMINAL mode, procedure
procedure LCU_switchon_w_D2_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    double drain2_v = 1.4; //Drain2 voltage in V
}{
    //Clear potential failure mode
    Set_LO_Nominal_block_fm();
    //
    //We use a constant frequency for each band, regardless of the input
    double[] result_d = CalibrationReader("name_keyfreq",["keyfreq","midfreq","keyfreqwarm","keyfreq_dummy"],band,0.0);
    lo_freq = result_d[0];
    //this is for cold operations
    //   lo_freq = result_d[2];   //this is for warm operations
    //   lo_freq = result_d[3];     //this is for dummy operations
    ////FM_CUS_11.5: replace keyfreq by the only allowed frequency for warm IST
    //For band 7b, 1723.5 may be problematic. Take mid freq. instead
    //if (band == "7b") {
    //  lo_freq = result_d[1];  
    //  }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    //double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["switch_on_delay"],band,lo_freq);
    int switch_on_delay = iround(result[0]{0});
    //
    //Send command: expect that we have already switched to NOMINAL
    //Contrary to QM, the channel is automatically switched ON
    HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,switch_on_delay);
    //
    //Set heater to their switch-on value
    HL_heater_block_fm(band,"nominal");
}

// Get maximum commanding time jitter which has to be added as margin
int procedure GetMaxTimeJitter {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] dead = CalibrationReader("timejitter",["timejitter"],band,lo_freq);

    return iceil(dead[0]);
}

// IV curve with magnets set to 0, block
block IVcurve_with_zero_magnet_fm HIFI 3214 {
    string band = "1a";
}{
    //Start_block() ;   
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["bias_min_h","bias_max_h","bias_steps_h","bias_min_v","bias_max_v","bias_steps_v"],band,0.0);
    //H polar
    double bias_min_h = result_d[0]{0};
    double bias_max_h = result_d[1]{0};
    int steps_h = iround(result_d[2]{0});
    //V polar
    double bias_min_v = result_d[3]{0};
    double bias_max_v = result_d[4]{0};
    int steps_v = iround(result_d[5]{0});
    //Bias to set at end of IVC
    //Need a representative frequency: take keyfreq
    double[] result = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result[0];
    //
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v","norm_magn_h","norm_magn_v"],band,lo_freq);
    double bias_h = result_d[0]{0};
    double bias_v = result_d[1]{0};
    //Magnets are set to 0
    double magnetcurrent_h = 0.0;
    double magnetcurrent_v = 0.0;
    //The IVCurve is done on the smallest range and the finest step
    double bias_min = max(bias_min_h,bias_min_v);
    double bias_max = min(bias_max_h,bias_max_v);
    int steps = iround(max(double(steps_h),double(steps_v)));
    //
    //First set magnets to max.
    double magnet_current_max_h = 0.0;
    double magnet_current_max_v = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
        magnet_current_max_h = result_d[0]{0};
        magnet_current_max_v = result_d[1]{0};
    }
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_current_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_current_max_v);
    delay(1);
    //Perform IV curve
    IVcurve(band,bias_min,bias_max,steps,magnetcurrent_h,magnetcurrent_v,bias_h,bias_v);
}

// HRS partial configuration, procedure
// Configures the LO and attenuators with att. input: all the same
procedure HRS_config_att_lo_w_att_fm {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["mr","mr"]; //HRS resolution code
    double new_att = 15.5; //Att. value to apply to all
}{
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double hrsH_ATT_U1 = new_att;
    double hrsH_ATT_L1 = new_att;
    double hrsH_ATT_U2 = new_att;
    double hrsH_ATT_L2 = new_att;
    double hrsH_ATT_U3 = new_att;
    double hrsH_ATT_L3 = new_att;
    double hrsH_ATT_U4 = new_att;
    double hrsH_ATT_L4 = new_att;
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double hrsV_ATT_U1 = new_att;
    double hrsV_ATT_L1 = new_att;
    double hrsV_ATT_U2 = new_att;
    double hrsV_ATT_L2 = new_att;
    double hrsV_ATT_U3 = new_att;
    double hrsV_ATT_L3 = new_att;
    double hrsV_ATT_U4 = new_att;
    double hrsV_ATT_L4 = new_att;
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb or hr keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_ATT_U1,hrsH_ATT_L1,hrsH_ATT_U2,hrsH_ATT_L2,hrsH_ATT_U3,hrsH_ATT_L3,hrsH_ATT_U4,hrsH_ATT_L4,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
    // 
    //delay(hrs_config_delay);
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsV_ATT_U1,hrsV_ATT_L1,hrsV_ATT_U2,hrsV_ATT_L2,hrsV_ATT_U3,hrsV_ATT_L3,hrsV_ATT_U4,hrsV_ATT_L4,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
    // 
    delay(hrs_config_delay);
}

//HIFI vector scan, block
//Check vector scan from safe to values close to BLUE MAX
block Vector_scan_BLUE_LIMIT_block_fm HIFI 3672 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    drain2_v_start = drain2_safe;
    //
    double drain2_max = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //For bands 1 to 5, scan will be done with increasing drain2 voltages
    //
    //For bands 6 to 7, scan will be done with decreasing drain2 voltages: NOT FOR THIS TEST !!
    if(band == "6a" || band == "7a" || band == "6b" || band == "7b") {
        //step_drain2_v = -1.0*step_drain2_v;
        //drain2_v_start = drain2_max;
        //Also, it probably makes no sense to go down to the safe value
        drain2_v_start = drain2_safe + 0.45;
        //i.e. go to 1.7
        //Need to check that drain2_v_start has not got above the blue max
        //If so, the range to scan is not so big so we stick to the safe value
        //as minimum drain2 for the scan
        if(drain2_v_start >= drain2_max) {
            drain2_v_start = drain2_safe;
        }
    }
    //
    result = ConfigurationReader(name_configlotune,["nsteps","step_time"],band,lo_freq);
    int nsteps = iround(result[0]{0});
    double step_drain2_v = -1.0 * (drain2_max - drain2_v_start) / double(nsteps - 1);
    drain2_v_start = drain2_max;
    double step_time = 5.0;
    //result[1]{0};
    //
    //Preliminary configuration at high Vd2
    //
    //Compute config_lo_delay: new approach: use ramp-up time
    result = ConfigurationReader("name_delays",["lock_lo_delay","vd2_rampup_speed"],band,lo_freq);
    int config_lo_delay = iceil(result[0]{0} + (drain2_v_start - drain2_safe) / result[1]{0});
    //Old approach: fixed delay
    //result = ConfigurationReader("name_delays",
    //		      ["config_lo_delay"],band, lo_freq); 
    //int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    //delay(1);
    //Execute vector scan 
    Hifi_HIFI_vector_scan($BBID);
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

// WBS comb, block
block WBS_calibration_block_fm HIFI 3796 {
}{
    //Initial configuration
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_att_band4_comb","hwh_att_band3_comb","hwh_att_band2_comb","hwh_att_band1_comb","hwh_att_in_comb"],"1a",0.0);
    int hwh_att_band4 = iround(result_d[0]{0});
    int hwh_att_band3 = iround(result_d[1]{0});
    int hwh_att_band2 = iround(result_d[2]{0});
    int hwh_att_band1 = iround(result_d[3]{0});
    int hwh_att_in = iround(result_d[4]{0});
    //    
    Hifi_HIFI_WBS_Calibrate($BBID,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //Apply delay
    result_d = ConfigurationReader("name_delays",["wbs_new_comb_delay"],"1a",0.0);
    int wbs_new_comb_delay = iround(result_d[0]{0});
    delay(wbs_new_comb_delay);
    //
}

// Slow chop integration at source position OFF-ON-ON-OFF...
block HIFISlowChopOnIntegration HIFI 6031 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_slow_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_M3left","chop_M3right"],rates);
}

//Generic procedure to launch engineering scan applied to chopper rotation, procedure
procedure Engineering_scan_for_chopper_rotation {
    double targetAngle = 0.0; //Target chopper voltage
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50]; // HIF_N_samples_1
    int samplesAfter = 1000 in [0,1000]; // HIF_N_samples_2
}{
    //
    targetAngle = Check_Chopper_Prime_Redundant(targetAngle);
    HIFI_Chopper_scan_fast_proc_fm(milliSecSample,targetAngle,samplesBefore,samplesAfter);
    //
    // delay calculation
    int nb_HK = 1;
    //For this TC, the 2 last HK fields are blanked out
    int millisecondsUsed = 1000 + 10 + milliSecSample * nb_HK * (samplesBefore + samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //
}

//////////////////////////////////////////////////////////
// Parameter scans
////////////////////////////
//LO parameter scan with HotCold measurement
procedure LCU_power_scan_with_Tsys {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4
    double lo_freq = 500.0; //LO frequency
    double param_min = 1.0; //Min. of scanned parameter
    double param_max = 2.0; //Max. of scanned parameter
    double step_size = 0.1; //Step size
    string param_name = "D2"; //Code of scanned parameter: M1,M2,G1,G2,D1,D2.
    int integ_time = 4; //Total integration time in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Configure and tune backends
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //   
    //Configure and tune backends
    if(backend == "wbs" || backend == "both") {
        WBS_calib_fm(band);
        WBS_config_block_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration after tuning
    int[] res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d1_v","d2_v"],band,lo_freq);
    double drain1_safe = cresult[0];
    double drain2_safe = cresult[1];
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1_v = result[0]{1};
    string curlim2_v = result[1]{1};
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //First set to nominal values
    HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_safe,curlim1_v,drain2_safe,curlim2_v,macro_checksum,config_lo_delay);
    //
    double current_param = param_min;
    //Loop up on parameter of interest, all other values set to
    //optimum value at the frequency of interest.
    while(current_param <= param_max) {
        //Identify parameter to be scanned.
        if(param_name == "M1") {
            m1_v = current_param;
        }
        if(param_name == "M2") {
            m2_v = current_param;
        }
        if(param_name == "G1") {
            gate1_v = current_param;
        }
        if(param_name == "G2") {
            gate2_v = current_param;
        }
        if(param_name == "D1") {
            drain1_v = current_param;
        }
        if(param_name == "D2") {
            drain2_v = current_param;
        }
        HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,config_lo_delay);
        //
        current_param = current_param + step_size;
        //Now take HotCold spectrum
        Hot_cold(band,hrs_mode,backend,res[0] * res[1],"tp",0,0);
        //
    }
    //Back to nominal values
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    plevel_v = result[0]{0};
    m1_v = result[1]{0};
    m2_v = result[2]{0};
    m3_v = result[3]{0};
    d2_step = iround(result[4]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    gate1_v = cresult[0];
    gate2_v = cresult[1];
    drain1_v = cresult[2];
    drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    freq_nx = iround(result[0]{0});
    //Compute lsu_main and offset
    resu = ComputeLSU_A_M_R(band,lo_freq);
    lsu_main = resu[0];
    lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    macro_checksum = iround(result[0]{0});
    //
    HIFI_Configure_LCU_block_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum,config_lo_delay);
    //
}

// thermal tests
block Thermal_warm_fm HIFI 3283 {
    string band = "1a"; // HIFI band
    double lo_freq = 522.0; //LO frequency
    string polar = "H" in ["H","V"]; //Mixer polarization: H or V
}{
    //Start_block();
    //Polarization selection: the unused polar will have parameters kept to 0
    double filter_H = 0.0;
    double filter_V = 0.0;
    if(polar == "H") {
        filter_H = 1.0;
    } else {
        filter_V = 1.0;
    }
    {double,string}[] result_d = ConfigurationReaderWarm("name_confilfpu",["band"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    //
    //Get Targetted values for magnet, mixer bias, heater time and diplexer
    double[] cresult_d = CalibrationReader("name_configthermal",["dipl_h","magn_h","mbias_h","heat_h","dipl_v","magn_v","mbias_v","heat_v"],band,0.0);
    double target_dipl_h = cresult_d[0];
    double target_magn_h = cresult_d[1];
    double target_mbias_h = cresult_d[2];
    double target_heat_h = cresult_d[3];
    double target_dipl_v = cresult_d[4];
    double target_magn_v = cresult_d[5];
    double target_mbias_v = cresult_d[6];
    double target_heat_v = cresult_d[7];
    //
    int diplex_h_ctrl_mode = 0;
    //this is HF_CH1_DPFPP1
    //
    double volt_H_FIF_1 = 0.0;
    double curr_H_FIF_1 = 0.0;
    double volt_H_FIF_2 = 0.0;
    double curr_H_FIF_2 = 0.0;
    //
    double volt_H_SIF_1 = 0.0;
    double curr_H_SIF_1 = 0.0;
    double volt_H_SIF_2 = 0.0;
    double curr_H_SIF_2 = 0.0;
    double volt_H_SIF_3 = 0.0;
    double curr_H_SIF_3 = 0.0;
    // 
    int diplex_v_ctrl_mode = 0;
    //this is HF_CV1_DPFPP1
    //
    double volt_V_FIF_1 = 0.0;
    double curr_V_FIF_1 = 0.0;
    double volt_V_FIF_2 = 0.0;
    double curr_V_FIF_2 = 0.0;
    //
    double volt_V_SIF_1 = 0.0;
    double curr_V_SIF_1 = 0.0;
    double volt_V_SIF_2 = 0.0;
    double curr_V_SIF_2 = 0.0;
    double volt_V_SIF_3 = 0.0;
    double curr_V_SIF_3 = 0.0;
    //
    string chop_sine_s = "ON";
    string chop_loop = "CLOSE";
    result_d = ConfigurationReaderWarm("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3"],band,lo_freq);
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    result_d = ConfigurationReaderWarm("name_confilfpu",["calibrator_current_on"],band,lo_freq);
    double calibcurrent = result_d[0]{0};
    double bias_H = 0.0;
    double magnetcurrent_H = 0.0;
    double diplex_H = 0.0;
    double bias_V = 0.0;
    double magnetcurrent_V = 0.0;
    double diplex_V = 0.0;
    result_d = ConfigurationReaderWarm("name_confilfpu",["chop_cold"],band,lo_freq);
    double chopper = result_d[0]{0};
    chopper = Check_Chopper_Prime_Redundant(chopper);
    //
    //Start modification of FPU parameters - This is also the 0 of the test clock
    //1. Initial configuration with the chopper moving to M3 middle
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    delay(300);
    //
    //2. Move diplexer: values depend on frequency
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(filter_H * result_d[0]{0});
        diplex_v_ctrl_mode = iround(filter_V * result_d[1]{0});
        diplex_H = target_dipl_h * filter_H;
        diplex_V = target_dipl_v * filter_V;
    }
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(300);
    //
    //3. Do action corresponding to IF2 on: All SIF parameters are set
    //
    //
    result_d = ConfigurationReaderWarm("name_confilfpu",["sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    volt_H_SIF_1 = filter_H * result_d[0]{0};
    curr_H_SIF_1 = filter_H * result_d[1]{0};
    volt_H_SIF_2 = filter_H * result_d[2]{0};
    curr_H_SIF_2 = filter_H * result_d[3]{0};
    volt_H_SIF_3 = filter_H * result_d[4]{0};
    curr_H_SIF_3 = filter_H * result_d[5]{0};
    // 
    result_d = ConfigurationReaderWarm("name_confilfpu",["sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    volt_V_SIF_1 = filter_V * result_d[0]{0};
    curr_V_SIF_1 = filter_V * result_d[1]{0};
    volt_V_SIF_2 = filter_V * result_d[2]{0};
    curr_V_SIF_2 = filter_V * result_d[3]{0};
    volt_V_SIF_3 = filter_V * result_d[4]{0};
    curr_V_SIF_3 = filter_V * result_d[5]{0};
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(1200);
    //
    //4. Do action corresponding to IF1 on: All FIF parameters are set
    //
    result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_h","fif1c_h","fif2v_h","fif2c_h"],band,lo_freq);
    volt_H_FIF_1 = filter_H * result_d[0]{0};
    curr_H_FIF_1 = filter_H * result_d[1]{0};
    volt_H_FIF_2 = filter_H * result_d[2]{0};
    curr_H_FIF_2 = filter_H * result_d[3]{0};
    //
    result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v"],band,lo_freq);
    volt_V_FIF_1 = filter_V * result_d[0]{0};
    curr_V_FIF_1 = filter_V * result_d[1]{0};
    volt_V_FIF_2 = filter_V * result_d[2]{0};
    curr_V_FIF_2 = filter_V * result_d[3]{0};
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(1200);
    //
    //5. Magnet current to max.
    if(band_nb <= 5) {
        result_d = ConfigurationReaderWarm("name_confilfpu",["magnet_current_max_v","magnet_current_max_h"],band,lo_freq);
        magnetcurrent_H = filter_H * result_d[1]{0};
        magnetcurrent_V = filter_V * result_d[0]{0};
        //
        HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
        delay(5);
        //Set to targetted values
        magnetcurrent_H = filter_H * target_magn_h;
        magnetcurrent_V = filter_V * target_magn_v;
        //
        HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
        delay(600);
    }
    //
    //6. Bias voltage to dedicated value for thermal test
    bias_H = filter_H * target_mbias_h;
    bias_V = filter_V * target_mbias_v;
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(600);
    //
    //7. Bias voltage back to null
    bias_H = 0.0;
    bias_V = 0.0;
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(600);
    //
    //8. Magnet current back to null
    if(band_nb <= 5) {
        magnetcurrent_H = 0.0;
        magnetcurrent_V = 0.0;
        HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
        delay(600);
    }
    //
    //9. Do action corresponding to IF1 off: FIF parameters are set to standby
    //
    result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],"0",0.0);
    //
    volt_H_FIF_1 = result_d[1]{0};
    curr_H_FIF_1 = result_d[2]{0};
    volt_H_FIF_2 = result_d[3]{0};
    curr_H_FIF_2 = result_d[4]{0};
    //
    {double,string}[] result_d2 = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],"0",0.0);
    //
    volt_V_FIF_1 = result_d2[0]{0};
    curr_V_FIF_1 = result_d2[1]{0};
    volt_V_FIF_2 = result_d2[2]{0};
    curr_V_FIF_2 = result_d2[3]{0};
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(1200);
    //
    //10. Do action corresponding to IF2 off: SIF parameters are set to standby
    //
    volt_H_SIF_1 = result_d[5]{0};
    curr_H_SIF_1 = result_d[6]{0};
    volt_H_SIF_2 = result_d[7]{0};
    curr_H_SIF_2 = result_d[8]{0};
    volt_H_SIF_3 = result_d[9]{0};
    curr_H_SIF_3 = result_d[10]{0};
    //
    volt_V_SIF_1 = result_d2[4]{0};
    curr_V_SIF_1 = result_d2[5]{0};
    volt_V_SIF_2 = result_d2[6]{0};
    curr_V_SIF_2 = result_d2[7]{0};
    volt_V_SIF_3 = result_d2[8]{0};
    curr_V_SIF_3 = result_d2[9]{0};
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    delay(1200);
    //
    //11. Diplexer back to null
    if(band_nb <= 2 || band_nb == 5) {
        //No action
    } else {
        diplex_H = 0.0;
        diplex_V = 0.0;
        //
        HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
        delay(300);
    }
    //12. Check heater current effect on temperature: Let current ON
    //    during the standard deflux time.
    //We will bias the junction to check when 
    //the heater effect is effective
    result_d = ConfigurationReaderWarm("name_confilfpu",["bias_very_low_h","bias_very_low_v"],band,lo_freq);
    bias_H = filter_H * result_d[0]{0};
    bias_V = filter_V * result_d[1]{0};
    Mixerbias(bias_H,bias_V);
    //
    //Get time during which one wants to send the pulse
    double max_heater_time_h = target_heat_h * 1000.0;
    //in msec
    double max_heater_time_v = target_heat_v * 1000.0;
    //in msec
    //Start to send the pulse
    //Comment: Hifi_HIFI_Set_SIS_heaters($BBID,max_heater_time_h,max_heater_time_v);
    //This command is not yet available, so we use single_commands
    //
    if(polar == "H") {
        Hifi_HIFI_HF_CH1_DHTR_C($BBID,max_heater_time_h);
        delay(iceil(max_heater_time_h / 1000.0) + 1);
    } else {
        Hifi_HIFI_HF_CV1_DHTR_C($BBID,max_heater_time_v);
        delay(iceil(max_heater_time_v / 1000.0) + 1);
    }
    //
    //13. Heater back to 0: it is done by essence after SIS_heater is complete.
    //Extra delay to cool down
    delay(600);
    //
}

{string,double,double}[] procedure HifiMappingModeDBSCrossSequencerInit {
    string modeName = "cross";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // inherit from dbs-raster mode
    {string,double,double}[] retvalues = HifiMappingProcDBSRasterSequencerInit(naifid,ra,dec,{0.0,double(npoints / 2) * stepsize},2,stepsize,npoints,band,lo_freq,effResolution,continuumDetection,oneGHzReference,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);

    return retvalues;
}

//
// Chopper scan, block (IF power as function of chopper position)
block Chopper_scan_fm HIFI 3260 {
    string band = "1a"; // HIFI band
    double chopper_pos_min = -7.0; //minimum chopper position
    double chopper_pos_max = 8.0; //maximum chopper position
    int n_steps = 300; //number of steps
    int integ_time = 4; //Total integration time in sec.: at least 2sec !  
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "tp" in ["tp","slowchop","fastchop"]; //modulation mode between hot/cold: tp, slowchop, fastchop
    int n_wbs1 = 20;
    int n_hrs_trans = 1;
    bool ref_position = false; //Do we take a reference spectrum every 100sec ?
    bool shutter_used = false;
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    Start_block();
    //
    int steps = 0;
    int steps_done = 0;
    int steps_wanted = n_steps;
    if(steps_wanted < 1) {
        steps_wanted = 1;
    }
    double chopper_pos = 0.0;
    double stepsize = 0.0;
    if(steps_wanted > 1) {
        stepsize = (chopper_pos_max - chopper_pos_min) / (double(steps_wanted) - 1.0);
    }
    //Move first half way to the first scanned position to
    //avoid hitting the end stop
    double intermediate_chopper_pos = (chopper_pos_max + chopper_pos_min) / 2.0;
    intermediate_chopper_pos = Check_Chopper_Prime_Redundant(intermediate_chopper_pos);
    HIFI_CPR_Chopper_Rot_proc_fm(intermediate_chopper_pos);
    //Rotate chopper
    Hifi_HIFI_non_periodic_hk_FCU();
    //To get sent voltage
    delay(1);
    //
    int start_stamp = time();
    int elapsed_time = 0;
    while(steps_done < steps_wanted) {
        steps = steps_wanted - steps_done;
        if(steps > n_steps) {
            steps = n_steps;
        }
        chopper_pos = chopper_pos_min + double(steps_done) * stepsize;
        if(chopper_pos > 8.5) {
            chopper_pos = 8.5;
            //Cannot go over 8.5 Volts
        }
        //Start scan
        //If shutter is not used, we chop against the middle of the scan span
        double chopper_pos_middle = 0.5 * (chopper_pos_min + chopper_pos_max);
        //If shutter is used, we chop against M3 middle
        if(shutter_used) {
            {double,string}[] result_d = ConfigurationReader("name_confilfpu",["chop_M3"],band,0.0);
            chopper_pos_middle = result_d[0]{0};
        }
        //Acquire spectrum: check which spectroscopic mode in use
        //Compute data-rate
        double[] rates = ILT_datarate_proc_fm(band,backend,chopmode,integ_time);
        //Total power case
        if(chopmode == "tp") {
            chopper_pos = Check_Chopper_Prime_Redundant(chopper_pos);
            HIFI_CPR_Chopper_Rot_proc_fm(chopper_pos);
            //Rotate chopper
            Hifi_HIFI_non_periodic_hk_FCU();
            //To get sent voltage
            delay(1);
            HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
            //Get spectrum
            //
            //Additional delay to work-around problem with SCOS jitter, see SPR-1109
            delay(1);
            //Check whether an additional spectrum on initial position needs to be taken
            elapsed_time = time() - start_stamp;
            if(ref_position) {
                if(elapsed_time >= 100) {
                    chopper_pos_min = Check_Chopper_Prime_Redundant(chopper_pos_min);
                    HIFI_CPR_Chopper_Rot_proc_fm(chopper_pos_min);
                    //Rotate chopper to initial scan position
                    Hifi_HIFI_non_periodic_hk_FCU();
                    //To get sent voltage
                    delay(1);
                    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
                    //Get spectrum
                    //
                    start_stamp = time();
                }
            }
        }
        if(chopmode == "slowchop") {
            // set data rates
            non_ess_hk_data_rate(rates[2] / 1024.0);
            data_rate(rates[0] / 1024.0);
            //
            HIFI_Spectr_slow_chop_proc_fm(chopper_pos_middle,chopper_pos);
            Apply_Slow_Chop_delay(integ_time,band,backend);
            //Additional delay to work-around problem with SCOS jitter, see SPR-1109
            delay(1);
            // reset data rates
            non_ess_hk_data_rate(rates[1] / 1024.0);
            data_rate(0.0);
        }
        if(chopmode == "fastchop") {
            // set data rates
            non_ess_hk_data_rate(rates[2] / 1024.0);
            data_rate(rates[0] / 1024.0);
            //
            HIFI_Spectr_fast_chop_proc_fm(chopper_pos_middle,chopper_pos,n_wbs1,n_hrs_trans);
            Apply_Fast_Chop_delay(integ_time,1,band,backend);
            //Additional delay to work-around problem with SCOS jitter, see SPR-1109
            delay(1);
            // reset data rates
            non_ess_hk_data_rate(rates[1] / 1024.0);
            data_rate(0.0);
        }
        //
        steps_done = steps_done + 1;
    }
}

//HIFI-COP-2.3-Param-Scan for total time calculation
procedure Parameter_Scan_MOIS_proc_ops {
    int index = 1 in [1,7]; // Test case index as of config_paramscan_COP.config
    int phase = 1 in [1,2]; //Measurement phase
    int integ_time = 4; //Integration time PER PHASE for the Tsys slowchop measurement  
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    bool config_only = true; //whether we only configure ("true") or run also Stab and Tsys 
}{
    int start = time();
    //
    //Read all band+param to perform
    string tab = "config_paramscan_COP.config";
    int total = table_size(tab);
    double lo_freq = dlookup(tab,"" + index,"lofreq");
    string band = slookup(tab,"" + index,"band");
    double m1_min = dlookup(tab,"" + index,"m1_1");
    double m1_max = dlookup(tab,"" + index,"m1_2");
    double m1_step = dlookup(tab,"" + index,"m1_step");
    double m2_min = dlookup(tab,"" + index,"m2_1");
    double m2_max = dlookup(tab,"" + index,"m2_2");
    double m2_step = dlookup(tab,"" + index,"m2_step");
    double bias_min = dlookup(tab,"" + index,"bias_1");
    double bias_max = dlookup(tab,"" + index,"bias_2");
    double bias_step = dlookup(tab,"" + index,"bias_step");
    double imix_min = dlookup(tab,"" + index,"imix_1");
    double imix_max = dlookup(tab,"" + index,"imix_2");
    double imix_step = dlookup(tab,"" + index,"imix_step");
    double m1 = 0.0;
    double m2 = 0.0;
    double bias = 0.0;
    double imix = 0.0;
    mois_comment("Parametric scan investigation in band " + band + " at " + lo_freq + " GHz");
    mois_comment("Execution of this procedure requires use of dedicated TPF files");
    //General parameters for spectroscopy
    string backend = "both";
    string chopmode = "slowchop";
    double sampling_rate = 3.0;
    //Sampling rate: 2 (2 HRS-H + 2 HRS-V), 4 (HRS-H + HRS-V, 2 HRS-H or 2 HRS-V) or 8 (1 HRS-H or 1 HRS-V) Hz
    double hrs_h_1 = 7.4;
    //Position in IF of HRS-H sub-band 1
    double hrs_h_2 = 7.4;
    //Position in IF of HRS-H sub-band 2
    double hrs_v_1 = 7.4;
    //Position in IF of HRS-V sub-band 1
    double hrs_v_2 = 7.4;
    //Position in IF of HRS-V sub-band 2
    double[] hrs_subband = [hrs_h_1,hrs_h_2,hrs_v_1,hrs_v_2];
    string hrs_polarization = "B";
    //HRS polarization: selection works only for 4 and 8 Hz
    int n = 1466;
    //Switch-on LO
    mois_step("LO switch-on");
    LCU_switchon_proc_fm(band);
    //Wait an extra delay of 1 min for short term stabilization
    delay(60);
    //
    //FPU configuration
    mois_step("FPU configuration");
    Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
    //Phase 1 measurement: loop on M1 and M2
    mois_step("Start loop on multipliers");
    string name_configlcu = "name_configlcu_b";
    //
    if(phase == 1) {
        m1 = m1_min;
        //Loop on M1
        while(m1 <= m1_max) {
            //Loop on m2: cancelled for the moment - SCR-2460
            m2 = m2_min;
            //while (m2<=m2_max) {
            // 
            //Implementation of SCR-2460: for the time being, M2 is fixed to its nominal value - no scan
            {double,string}[] result = ConfigurationReader(name_configlcu,["m2_v"],band,lo_freq);
            m2 = result[0]{0};
            //Tune LO at standard target
            LO_tuning_w_M1M2_block_fm(band,lo_freq,m1,m2);
            message(band + ", " + lo_freq + ", " + m1 + ", " + m2);
            //
            if(config_only == false) {
                //Do stab and Tsys as well
                //Tsys measurement
                WBS_calib_fm(band);
                WBS_tune_proc_fm(band);
                HRS_tune_block_fm(band);
                //Configure spectroscopy for slowchop hotcold
                int[] res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
                int total_time = res[0] * res[1];
                Hot_cold(band,hrs_mode,backend,total_time,chopmode,0,0);
                //
                //HRS fast stability measurment
                Stability_fast_proc_fm(band,n,hrs_subband,sampling_rate,hrs_polarization);
                //
                //}
                //m2 = m2+m2_step;       
            }
            //end loop m2
            m1 = m1 + m1_step;
        }
        //end loop M1
    }
    //Phase 2 measurement: loop on bias and Imix
    if(phase == 2) {
        //Configure at nominal M1,M2 (i.e. they are in the LCU safety table release)
        LCU_config_nominal_proc_fm(band,lo_freq);
        imix = imix_min;
        //Loop on Imix
        while(imix <= imix_max) {
            //Loop on bias
            bias = bias_min;
            while(bias <= bias_max) {
                //
                //Apply biases
                //In case of band 6 or 7, go via max first
                if(band == "7b") {
                    result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
                    //First go to 4mV
                    Mixerbias_block_fm(result[0]{0},result[1]{0});
                    //Then to nominal
                    Mixerbias_block_fm(bias,bias);
                }
                // 
                //Tune LO at dedicated target (use of H mixer)
                LO_tuning_w_targetC_block_fm(imix / 1000.0,band,lo_freq,"H");
                //
                //Tsys measurement
                WBS_calib_fm(band);
                WBS_tune_proc_fm(band);
                HRS_tune_block_fm(band);
                //Configure spectroscopy for slowchop hotcold
                res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
                total_time = res[0] * res[1];
                Hot_cold(band,hrs_mode,backend,total_time,chopmode,0,0);
                //
                //HRS fast stability measurment
                Stability_fast_proc_fm(band,n,hrs_subband,sampling_rate,hrs_polarization);
                //
                bias = bias + bias_step;
            }
            //end loop bias
            imix = imix + imix_step;
        }
        //end loop imix
    }
}

// get backend resolution and effective noise resolution
double[] procedure GetBackendResolution {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    int res_mode = 0; // coding for the backend resolution mode
}{
    if(res_mode < 0 || res_mode > 3) {
        double[] resol = CalibrationReader("backendresolution",["wbs_resolution","wbs_fluct_ratio"],band,lo_freq);
    }
    if(res_mode == 0) {
        resol = CalibrationReader("backendresolution",["hrs_high_resolution","hrs_fluct_ratio"],band,lo_freq);
    }
    if(res_mode == 1) {
        resol = CalibrationReader("backendresolution",["hrs_normal_resolution","hrs_fluct_ratio"],band,lo_freq);
    }
    if(res_mode == 2) {
        resol = CalibrationReader("backendresolution",["hrs_low_resolution","hrs_fluct_ratio"],band,lo_freq);
    }
    if(res_mode == 3) {
        resol = CalibrationReader("backendresolution",["hrs_wide_resolution","hrs_fluct_ratio"],band,lo_freq);
    }

    return resol;
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the DBS raster mode
procedure JupiterDBSRaster_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size
    int n_seq = 1; // Number of continuous chop cycles
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF cycles 
    int n_pointsperscan = 1; // Number of points measured before moving to the second pointing phase
    int n_loadinterval = 10; // number of nods before a load measurement
    int n_load = 0; // additional load measurements in one pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,10,0,10,20,21,0,0,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    bool iscross = false; // Whether we use a cross instead of a raster
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get all values from the telescope section  
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // Count phases by hand to allow simultaneous usage by Raster and Cross
    int iphase = 0;
    // There is no nod counter in the return values - count this by hand
    int inod = 0;
    // Do I have to make loads in short nods and subsequent holds?
    if(iscross) {
        bool holdforload = n_pointsperscan > 1;
    } else {
        holdforload = n_pointsperscan == 1 && n_loadinterval > n_cycles;
    }
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"jupiter");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
            iphase = iphase + 1;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            // The use of n_load differs by 1 from the other observing modes here
            for(int i1 = 1 .. n_load - 1) {
                HIFISlowChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle 
            HIFISlowChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            // n_pointsperscan=1, n_loadinterval > n_cycles
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == 1) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
            // Update phase counter
            iphase = iphase + 1;
        }
        // Second pointing phase
        if(state[0] == 7) {
            // second nod position
            HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            for(int i2 = 1 .. n_load - 1) {
                HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle 
            HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == 1) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
            // Update phase counter
            iphase = iphase + 1;
        }
        // Load nod
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
        }
        // Hold
        if(state[0] == 6) {
            // finished shift of instrument operations relative to pointing command
            runintostate = false;
        }
        // Final load
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

// Stability test, procedure
// Measurement of internal cold in FSW mode
// this is the CBB counterpart - no LOU retune involved
procedure Proc_stability_freqswitch_COP_CBB {
    string band = "1a"; // HIFI band
    double lo_freq = 522.0; //The LO frequency
    double freq_throw = 50.0; //The frequency throw in MHz
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total (co-added) integration time of a phase in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_cold_ang");
    //Look at M3
    //
    //Tune backends
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        HRS_tune_block_fm(band);
    }
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        //WBS calibration
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    //
    Stability_freqswitch_fm(band,n,integ_time,hrs_mode,backend);
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
    //2 sec. integration
}

////////////////////////////////////
// Fast chop DBS raster observing mode - special version for Jupiter
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcJupiterFastDBSRaster {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,100]; // Number of rows in the map
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the raster line
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Engineering - Jupiter - DBS Raster Map fastChop",{data_time,0,n_int_on,n_switch_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    // Two changes relative to the normal DBS raster
    // 1) The longer load duration is enforced by zero resolution
    {double,double} loadResolution = {0.0,effResolution{1}};
    // 2) I assume that the tuning duration does not depend on the tuning level
    // so that the normal pre_timing can be reused.
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = FastDBSRaster_pre_timing(nlines,npoints,band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    // Check for NoddingInRaster or NoddingOfRaster
    int scansize = pre_timing{10};
    if(scansize > 1) {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,double,double,int,int,int,int,int} tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        // Dummy call to spacecraft command
        int[] telescopetimes = nodding_of_raster_pointing(false,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double,int,int,int,double,double,int,int,int,int} tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        telescopetimes = nodding_raster_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSRaster_post_timing(pre_timing,telescopetimes,nlines,npoints,n_switch_on,n_cycles,load_interval,true);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    if(scansize > 1) {
        tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        // Call telescope command
        telescopetimes = nodding_of_raster_pointing(true,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        telescopetimes = nodding_raster_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        JupiterFastDBSRaster_commanding(band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,false);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastDBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints,n_cycles,n_seq * n_int_on * imax(n_load,1),tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//Single magnet scan
procedure Magnet_scan {
    string band = "1a"; // HIFI band
    double magnet_min_h = -10.0; // min magnet current
    double magnet_max_h = 15.0; // max magnet current
    int step_count_h = 10; // number of steps
    double step_duration = 0.1; // step duration
    double bias_h = 1.8; // bias voltage
    double magnet_min_v = -10.0; // min magnet current
    double magnet_max_v = 15.0; // max magnet current
    int step_count_v = 10; // number of steps
    double bias_v = 1.8; // bias voltage
}{
    int nbias = 1;
    if(step_duration > 0.15) {
        nbias = 2;
    }
    if(step_duration > 0.25) {
        nbias = 4;
    }
    if(step_duration > 0.45) {
        nbias = 5;
    }
    if(step_duration > 0.6) {
        nbias = 8;
    }
    if(step_duration > 0.7) {
        nbias = 10;
    }
    if(step_duration > 1.4) {
        nbias = 20;
    }
    int max_per_command = 40;
    int maxsteps = max_per_command / nbias;
    int steps = 0;
    int steps_done = 0;
    //We take the finest step possible
    double magnet_min = max(magnet_min_h,magnet_min_v);
    double magnet_max = min(magnet_max_h,magnet_max_v);
    int step_count = iround(max(double(step_count_h),double(step_count_v)));
    //
    double step = Stepsize(magnet_min,magnet_max,step_count,"hifi_HIF_mx_mg_step_C");
    double margin = Stepmargin(magnet_min,magnet_max,"hifi_HIF_mx_mg_step_C");
    int steps_wanted = 1 + iceil((magnet_max - magnet_min) / step);
    // force the last portion to less than maxsteps
    if(maxsteps * (steps_wanted / maxsteps) == steps_wanted) {
        steps_wanted = steps_wanted - 1;
    }
    //
    //Set magnet to maximum to avoid hysteresis
    {double,string}[] result = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
    double magnet_current_max_h = result[0]{0};
    double magnet_current_max_v = result[1]{0};
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_current_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_current_max_v);
    delay(1);
    //
    double magnet_current_h = 0.0;
    double magnet_current_v = 0.0;
    int duration_scan = 0;
    //Start scan: from max. to min. magnet downward.
    while(steps_done < steps_wanted) {
        steps = steps_wanted - steps_done;
        if(steps > maxsteps) {
            steps = maxsteps;
        }
        magnet_current_h = magnet_max_h - double(steps_done) * step;
        magnet_current_v = magnet_max_v - double(steps_done) * step;
        Hifi_HIFI_FCU_parameter_scan($BBID,nbias,steps,0.1,bias_h,bias_v,0.0,magnet_current_h,magnet_current_v,step + margin);
        duration_scan = iceil(double(steps * nbias) * 0.1);
        delay(duration_scan + 2);
        steps_done = steps_done + steps;
    }
}

// Chopper Response time with all possible combinations, block
// Due to current PTV restriction, need to go the starting
// position also via an engineering scan TC
block Chopper_Response_time_block_COP HIFI 3787 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50];
    int samplesAfter = 1000 in [0,1000];
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Start_block();
    //
    //We assume starting from HBB.
    //1. response time to go from HBB to CBB
    //Get cold position
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["chop_cold"],band,0.0);
    double targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation_COP(targetAngle,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    //
    //2. response time to go from CBB to M3 middle
    result_d = ConfigurationReader("name_confilfpu",["chop_M3"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation_COP(targetAngle,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    //
    //3. response time to go from M3 middle to CBB
    result_d = ConfigurationReader("name_confilfpu",["chop_cold"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation_COP(targetAngle,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    //
    //4. response time to go from CBB to HBB
    result_d = ConfigurationReader("name_confilfpu",["chop_hot"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation_COP(targetAngle,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    //
    //5. response time to go from HBB to M3 left
    result_d = ConfigurationReader("name_confilfpu",["chop_M3left"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation_COP(targetAngle,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    //
    //6. response time to go from M3 left to M3 right
    result_d = ConfigurationReader("name_confilfpu",["chop_M3right"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation_COP(targetAngle,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    //
    //7. response time to go from M3 right to M3 left
    result_d = ConfigurationReader("name_confilfpu",["chop_M3left"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation_COP(targetAngle,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    //
}

//Generic procedure to send chopper angle using the adequate instrument side
procedure HIFI_CPR_Chopper_Rot_RAW_proc_fm {
    int targetAngle = 0; // HF_CPR_Chopper_Rot
}{
    //check prime or redundant keyword
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant"],"0",0.0);
    if(result_d[0]{1} == "prime") {
        Hifi_HIFI_P_Chopper_Rot_RAW($BBID,targetAngle);
    } else {
        Hifi_HIFI_R_Chopper_Rot_RAW($BBID,targetAngle);
    }
}

//LO parameter scan without HotCold measurement
//for Band 5a
procedure LCU5a_power_scan_without_Tsys {
    string band = "5a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4
    double lo_freq = 1150.0 in [1127.0,1178.0]; //LO frequency
    double param_min = 1.0; //Min. of scanned parameter
    double param_max = 2.0; //Max. of scanned parameter
    double step_size = 0.1; //Step size
    string param_name = "D2"; //Code of scanned parameter: M1,M2,G1,G2,D1,D2.
}{
    error("This module is obsolete: use LCU_power_scan_without_Tsys  instead");
}

// Frequency switch
procedure HIFI_Spectr_fswitch_proc_aot {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // chop cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    // Call command
    Hifi_HIFI_Spectr_freq_switch($BBID);
    delay(2 * n_cycle * data_time);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

//Contingency for LOU temp FDIR modification
mode HifiManCmd_Dump_7AH_page {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
}{
    mois_comment("Procedure to dump the LCU memory at page 7AH");
    //StartMode_block_ops(); 
    //
    mois_step("Send memory dump command");
    Dump_7AH_page_block_mois();
    //
    StopMode_block_ops();
    // -> to issue last obsd/bbid
}

////////////////////////////////////
// Fast chop DBS raster  - cross observing mode
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcFastDBSCross {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the two raster lines
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Mapping - DBS Cross Map fastChop",{data_time,0,n_switch_on,n_int_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = FastDBSRaster_pre_timing(2,npoints,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,double[],double[],int[],double,double,int,int,int,int,int,int} tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = custom_map_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSCross_post_timing(pre_timing,telescopetimes,npoints,n_switch_on,n_cycles,load_interval,true);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBSCross_telescope(naifid,onPosition,stepsize,npoints,band,lo_freq,"",post_timing{1},n_cycles);
    telescopetimes = custom_map_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int scansize = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FastDBSRaster_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,true);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastDBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,2,npoints,n_cycles,n_seq * n_int_on * imax(n_load,1),tact);
    // Correct for double counting of central point
    // The central point is returned only
    double multiplier = sqrt(0.5);
    noisevalues{0} = noisevalues{0} * multiplier;
    noisevalues{1} = noisevalues{1} * multiplier;
    noisevalues{2} = noisevalues{2} * multiplier;
    noisevalues{3} = noisevalues{3} * multiplier;
    noisevalues{4} = noisevalues{4} / multiplier;
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Needs the chopper in open-loop mode !!
block Chopper_openloop_set_block_ops HIFI 7693 {
    int position = 0 in [0,1];
    string prime_or_redundant = "Prime" in ["Prime","Redundant"]; //Prime or Red 
}{
    int rot = 2048 + 70 * position;
    mois_step("Moving chopper to position " + rot + " in RAW units");
    //Prime/Red has no effect on RAW to send, only to the TC name
    if(prime_or_redundant == "Prime") {
        Hifi_HIFI_P_Chopper_Rot_RAW($BBID,rot);
    } else {
        Hifi_HIFI_R_Chopper_Rot_RAW($BBID,rot);
    }
    Hifi_HIFI_non_periodic_hk_FCU();
    //To get sent value
    mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to " + rot + " in RAW units");
    delay(2);
}

////////////////////////////////////
// Error reporting functions - containing some standard text
procedure CError {
    string errormessage = "Inconsistency detected."; // Error message
}{
    string fullmessage = "Internal HIFI observing mode error:<br>" + errormessage + "<br>Please, report this error together with the AOR file to the " + "Herschel Science Centre Helpdesk.";
    // To be replaced by a link to the SPR system when this can handle AOR files
    error(fullmessage);
}

// Auxiliary routine to check for bad map sizes
// 
procedure CheckReasonableLineNumber {
    int nlines = 1; // Number of OTF lines in a map
    bool isOtf = true; // whether this is an OTF of a raster map
}{
    // Give warning in case of "bad" map sizes
    // Here is a very bad place to make the test - it should rather go to HSPOT
    int divisors = 0;
    int[] divlist = [2,3,4,5];
    for(int idiv = 0 .. 3) {
        if(nlines % divlist[idiv] == 0) {
            divisors = divisors + 1;
        }
    }
    if(nlines > 10 && divisors < 2 || nlines > 6 && divisors < 1) {
        if(isOtf) {
            message("<strong>Warning:</strong> The map contains " + nlines + " lines. " + "This cannot be split efficiently into equal scans of " + "multiple lines. Try to change your map size.<br>");
        } else {
            message("<strong>Warning:</strong> The map contains " + nlines + " points. " + "This cannot be split efficiently into equal scans of " + "multiple points.Try to change your map size.<br>");
        }
    }
}

// Chopper Response time with all possible combinations, block
// Due to current PTV restriction, need to go the starting
// position also via an engineering scan TC
block Chopper_Response_time_block_fm HIFI 3687 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50];
    int samplesAfter = 1000 in [0,1000];
}{
    Start_block();
    //
    //We assume starting from HBB.
    //1. response time to go from HBB to CBB
    //Get cold position
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["chop_cold"],band,0.0);
    double targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation(targetAngle,milliSecSample,samplesBefore,samplesAfter);
    //
    //2. response time to go from CBB to M3 middle
    result_d = ConfigurationReader("name_confilfpu",["chop_M3"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation(targetAngle,milliSecSample,samplesBefore,samplesAfter);
    //
    //3. response time to go from M3 middle to CBB
    result_d = ConfigurationReader("name_confilfpu",["chop_cold"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation(targetAngle,milliSecSample,samplesBefore,samplesAfter);
    //
    //4. response time to go from CBB to HBB
    result_d = ConfigurationReader("name_confilfpu",["chop_hot"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation(targetAngle,milliSecSample,samplesBefore,samplesAfter);
    //
    //5. response time to go from HBB to M3 left
    result_d = ConfigurationReader("name_confilfpu",["chop_M3left"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation(targetAngle,milliSecSample,samplesBefore,samplesAfter);
    //
    //6. response time to go from M3 left to M3 right
    result_d = ConfigurationReader("name_confilfpu",["chop_M3right"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation(targetAngle,milliSecSample,samplesBefore,samplesAfter);
    //
    //7. response time to go from M3 right to M3 left
    result_d = ConfigurationReader("name_confilfpu",["chop_M3left"],band,0.0);
    targetAngle = result_d[0]{0};
    Engineering_scan_for_chopper_rotation(targetAngle,milliSecSample,samplesBefore,samplesAfter);
    //
}

// LO settling time for a LO sub-band change, 2nd block
// Block for second tuning
block LO_Settling_time_second_tuning_fm HIFI 3681 {
    string band_b = "1b" in ["1b","2b","3b","4b","5b","6b","7b"]; // HIFI band a
    int int_time2 = 600; //Integration time after first and second switch
    double lo_freq_b = 600.0; //LO frequency in sub-band b
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //
    //
    //Init and tune of LO: configuration from safe to tuned.
    LCU_config_nominal_proc_fm(band_b,lo_freq_b);
    LO_tuning_w_mixerchoice_proc(band_b,lo_freq_b,"H");
    //
    //Configure spectroscopy integration
    Configure_Spectrometer_proc_fm(band_b,int_time2,["wb1","wb1"],backend);
    //4 sec. integration
    //Take series of spectra during int_time2 seconds
    HIFI_Spectr_total_power_proc_fm(band_b,backend,int_time2);
    //
    //Now switch off LO sub-band
    LCU_switch_off_proc_fm();
}

//////////////////////////////////////////////////////////////////////////
// Auxiliary routine to guarantee  matching of telescope API with
// respect to map sizes and scan velocities
// 
{double,double,int} procedure ValidMapSize {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} linedistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines_tot = 1 in [1,240]; // Number of rows in the map
    double stepsize = 0.0050 in [0.0,0.13333]; // Distance between subsequent points in the OTF line
    int npoints_inp = 10 in [1,720]; // Number of data dumps per row
    int data_time = 4; // readout time
}{
    // Define maximum reduction - no reduction any more
    double eps = 1.0;
    // What is wanted
    double reqsize = stepsize * double(npoints_inp);
    // First evaluate valid step size
    double ratestep = 0.1 / 3600.0;
    double scanvelocity = stepsize / double(data_time);
    // Check for too low scanning speeds resulting in a discretization
    // error larger than half the step size
    if(scanvelocity < 2.0 * ratestep) {
        SError("Scan velocity too small for accurate map coverage.");
    }
    // Compute actual discretized rate
    double rate = double(iceil(scanvelocity * eps / ratestep)) * ratestep;
    double validstepsize = rate * double(data_time);
    // A message is the only feedback mechanism that we have here.
    double reldiff = (validstepsize - stepsize) * double(npoints_inp);
    if(abs(reldiff) > 0.5 * stepsize) {
        message("OTF readout is adjusted to occur every " + dformat(validstepsize * 3600.0,1) + "'' instead of the requested " + dformat(stepsize * 3600.0,1) + "''.<br>");
    }
    // 2. step: Extend the npoints number to match the telescope API
    double rowmin = 20.0 / 3600.0;
    double rowstep = 5.0 / 3600.0;
    // Correct for possible 1s jitter, i.e. enlarge stripes
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    double step1s = validstepsize * double(jitterdead) / double(data_time);
    // Implementation assumes that rowmin is an integer multiple of rowstep
    if(reqsize > rowmin) {
        double fullrowlength = double(iceil((reqsize * eps + step1s) / rowstep)) * rowstep;
    } else {
        fullrowlength = rowmin;
    }
    int npoints = imax(ifloor((fullrowlength - step1s) / validstepsize),2);
    // Iterate on fullrowlength to avoid overheads
    double dumpsize = double(npoints) * validstepsize + step1s;
    if(dumpsize > rowmin) {
        fullrowlength = double(iceil(dumpsize / rowstep)) * rowstep;
    } else {
        fullrowlength = rowmin;
    }
    // Message
    reldiff = fullrowlength - step1s - reqsize;
    if(abs(reldiff) > 0.5 * stepsize) {
        message("The length of all OTF stripes is adjusted to cover " + dformat(double(npoints) * validstepsize * 3600.0,1) + "'' instead of the requested " + dformat(reqsize * 3600.0,1) + "''.<br>");
    }
    // Granularity for d2
    // This is duplicated from OTF_telescope
    double linestep = 0.5 / 3600.0;
    double d2_req = AngleVectorLength(linedistance);
    double d2 = double(iceil(d2_req * eps / linestep)) * linestep;
    // Exception for the "impossible" case of spacings below 2arcsec
    if(d2 > 0.0) {
        d2 = max(d2,2.0 / 3600.0);
    }
    // Message 
    reldiff = (d2 - d2_req) * double(nlines_tot);
    if(abs(reldiff) > 0.5 * d2_req) {
        message("The OTF stripe distance is adjusted to " + dformat(d2 * 3600.0,1) + "'' instead of the requested " + dformat(d2_req * 3600.0,1) + "''.<br>");
    }

    return {fullrowlength,rate,npoints};
}

// Procedure to check whether fast chop frequency is high enough for 
// HRS internal integration and low enough for mechanical chopper constraints
//
procedure CheckFastChopFrequency {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int data_time = 10 in [4,128]; // data dump interval
    int n_int = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_data = 2; // Integration time counter
}{
    // Get timing parameters
    {int,int,int,int,int,int,int,int,int,int,int,int,int} timing = FastConfigureSpectroscopyParams(data_time,n_int,n_data,band,lo_freq,true);
    int del_wbs = timing{5};
    int t_acc_wbs = timing{6};
    int t_acc_hrs = timing{7};
    // Maximum phase length
    {double,string}[] result = ConfigurationReader("name_delays",["max_hrs_phase"],band,lo_freq);
    int max_hrs_phase = iround(result[0]{0});
    // Minimum chop phase length
    int min_wbs_phase = GetMinChopPhaseLength(band,lo_freq);
    // Checks
    if(t_acc_wbs + del_wbs < min_wbs_phase) {
        SError("Chop phases too short for chopper mechanics. Reduce chop frequency.");
    }
    if(t_acc_hrs > max_hrs_phase) {
        SError("Chop phase length too long for HRS. Increase chop frequency.");
    }
}

// Function returning generic HRS mode
string[] procedure GetHrsMode_proc_ops {
    string[] input_hrs_mode = ["wb","wb"]; // HRS resolution mode
}{
    string[] output_hrs_mode = ["wb","wb"];
    //Test all possible resolution modes
    //H-polar
    if(input_hrs_mode[0] == "hr" || input_hrs_mode[0] == "hr_high" || input_hrs_mode[0] == "hr_low") {
        output_hrs_mode[0] = "hr";
    }
    if(input_hrs_mode[0] == "mr") {
        output_hrs_mode[0] = "mr";
    }
    if(input_hrs_mode[0] == "lr") {
        output_hrs_mode[0] = "lr";
    }
    //V-polar
    if(input_hrs_mode[1] == "hr" || input_hrs_mode[1] == "hr_high" || input_hrs_mode[1] == "hr_low") {
        output_hrs_mode[1] = "hr";
    }
    if(input_hrs_mode[1] == "mr") {
        output_hrs_mode[1] = "mr";
    }
    if(input_hrs_mode[1] == "lr") {
        output_hrs_mode[1] = "lr";
    }
    //

    return output_hrs_mode;
}

//HIFI-COP-3-Tsys
procedure Tsys_COP_proc_ops {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int integ_time = 4;
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    int n_wbs1 = 0;
    int n_hrs_trans = 0;
    string chopmode = "slowchop";
}{
    //
    LCU_switchon_proc_fm(band);
    //Wait an extra delay of 1 min for short term stabilization
    delay(60);
    //
    HRS_config_block_fm(band,hrs_mode);
    //
    int[] res = [0,0];
    res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    int total_time = res[0] * res[1];
    //
    //Get the list of frequencies to be used for the scan
    string tab = "config_surveytsys.config";
    double bandnb = GetBandCode(band);
    double lofreqlow = dlookup(tab,"" + iceil(bandnb),"lofreqlow");
    double lofreqhigh = dlookup(tab,"" + iceil(bandnb),"lofreqhigh");
    double lofreqstep = dlookup(tab,"" + iceil(bandnb),"lofreqstep");
    //
    double current_LO = lofreqlow;
    bool endreached = false;
    //Loop on key frequencies per LO band
    while(current_LO <= lofreqhigh && endreached == false) {
        //     
        Init_MSA_HBB_fm(band,"CLOSE",current_LO,"ON");
        LO_tuning_block_fm(band,current_LO);
        WBS_calib_fm(band);
        //Does a magnet tuning: only up to band 5 since band6-7 have no magnets
        if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
            Magnet_tuning_block_fm(band,current_LO,"HRS",40);
            //for first freq of each LO band, deflux heater
            if(current_LO == lofreqlow && (band != "5a" || band != "5b")) {
                //Deflux heaters
                Heater_cop(band);
                //Second magnet tuning
                Magnet_tuning_block_fm(band,current_LO,"HRS",40);
            }
        }
        WBS_tune_proc_fm(band);
        HRS_tune_block_fm(band);
        // 
        Hot_cold(band,hrs_mode,backend,total_time,chopmode,n_wbs1,n_hrs_trans);
        //
        //Check last LO freq done
        if(current_LO == lofreqhigh && endreached == false) {
            endreached = true;
        }
        //Increase LO freq: truncate if step too high
        current_LO = current_LO + lofreqstep;
        if(current_LO > lofreqhigh && endreached == false) {
            current_LO = lofreqhigh;
        }
    }
}

// Get dead time for chopper motion on the sky
double procedure GetLoadChopDeadTime {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] dead = CalibrationReader("lchop_deadtime",["loadchop"],band,lo_freq);

    return dead[0];
}

/////////////////////////////////////////////////////////////////
// Second step of timing computation after telescope behaviour
// is known -  Spectral Scan frequency switch observing mode
// 
{int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},double,double,double} procedure SScanDoubleChop_post_timing {
    {int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} pre_timing = {16,16,16,16,21,11,1800,32,2,2,0,0,false,false,50,0}; // pre_timing parameter list
    int[] telescopetimes = [300,180,20,1,21,0];
    int grouplen = 1; // Number of frequencies to group into one cycle
    int groupnumber = 50; // Total umber of frequency groups
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
}{
    // Get all values from the pre_timing section
    int on_inttime = pre_timing{0};
    int off_inttime = pre_timing{1};
    int on_pointing = pre_timing{2};
    int off_pointing = pre_timing{3};
    int loadlength = pre_timing{4};
    int auxtunestep = pre_timing{5};
    int load_spacing = pre_timing{6};
    int n_loadinterval = pre_timing{7};
    int n_chop_on = pre_timing{8};
    int n_chop_off = pre_timing{9};
    int data_time_on = pre_timing{10};
    int data_time_off = pre_timing{11};
    bool end_load_on = pre_timing{12};
    bool end_load_off = pre_timing{13};
    int initlength = pre_timing{14};
    int dangling = pre_timing{15};
    // Get all values from the telescope section
    int telinit = telescopetimes[1];
    // Initial slew time
    int slewtime = telescopetimes[2];
    // Slew time to OFF
    int longslew = telescopetimes[4];
    // Actual slew time for load slew
    int pointwaittime = telescopetimes[3];
    // Idle time between two phases
    int tend = telescopetimes[5];
    // Final deceleration time
    //////////////////////////////////////////////////////////////////
    // Now we start the actual computations
    // Pointwaittime is used for tuning
    // In all non-tuning cycles, pointwaittime acts like a longer slew
    slewtime = slewtime + pointwaittime;
    longslew = longslew + pointwaittime;
    // Half tune step has to be rounded up
    int halftunestep = (auxtunestep + 1) / 2;
    int effhalftunestep = (auxtunestep - pointwaittime + 1) / 2;
    int shiftlength = halftunestep - effhalftunestep;
    // Correct pointing times
    on_pointing = on_pointing - shiftlength;
    off_pointing = off_pointing - shiftlength;
    // Check group length limited by load_interval
    int scan_time = on_pointing + off_pointing + slewtime;
    if(scan_time > load_spacing + slewtime && grouplen > 1) {
        SError("Frequency group length too large for load interval.");
    }
    // Compute load cycles and average times
    if(n_cycles > 1) {
        // How often do I have to perform a load slew
        // Never switch between short load and long load here
        if(n_loadinterval > 1) {
            int old_n_loadinterval = n_loadinterval;
            n_loadinterval = imax((load_spacing + slewtime) / scan_time,1);
            // fit with n_cycles
            n_loadinterval = imin(n_loadinterval,n_cycles);
            n_loadinterval = IMultiple(n_loadinterval,n_cycles);
            if(n_loadinterval <= 1) {
                n_loadinterval = old_n_loadinterval;
            }
        }
        // Determine need for final load measurement
        double rest = double(n_cycles * groupnumber % n_loadinterval) + 0.5;
        bool final_load = rest > 0.5001 * double(n_loadinterval);
        // part of integrations is added when not needed for tuning
        int n_add_on = effhalftunestep / (2 * data_time_on);
        int n_long_on = n_chop_on + n_add_on;
        int n_add_off = effhalftunestep / (2 * data_time_off);
        int n_long_off = n_chop_off + n_add_off;
        // Average times for noise estimate
        int longint_on = n_long_on * 2 * data_time_on;
        int longint_off = n_long_off * 2 * data_time_on;
        int numlong_on = 2 * (n_cycles / 2);
        double effchop_on = double(numlong_on * n_long_on + (n_cycles * grouplen - numlong_on) * n_chop_on) / double(grouplen * n_cycles);
        int numlong_off = 2 * ((n_cycles - 1) / 2);
        double effchop_off = double(numlong_off * n_long_off + (n_cycles - numlong_off) * n_chop_off) / double(n_cycles);
        int loadpercycle = n_cycles / n_loadinterval;
        double cycletime = double(on_pointing + off_pointing) + double(loadpercycle * longslew + (n_cycles - loadpercycle) * slewtime) / double(n_cycles);
        double tscan = (cycletime * double(n_cycles) - double(2 * halftunestep)) / double(n_cycles);
        // retuning does not increase drift
    } else {
        // Determine need for final load measurement
        if(groupnumber % 2 == 0) {
            rest = double(off_pointing);
        } else {
            rest = double(on_pointing);
        }
        final_load = rest > 0.5001 * double(load_spacing);
        // All cycles have the same length
        n_long_on = n_chop_on;
        n_long_off = n_chop_off;
        // Average times for noise estimate
        effchop_on = double(n_chop_on);
        effchop_off = double(n_chop_off);
        cycletime = double(on_pointing + off_pointing + longslew);
        tscan = cycletime - double(2 * effhalftunestep);
    }
    //////////////////////////////////////////////////////////////////////
    // Compute total duration
    initlength = initlength - effhalftunestep;
    shiftlength = effhalftunestep;
    // The initial time is no longer contained in the total time
    // int totaltime=imax(initlength,telinit);
    int totaltime = iround(cycletime * double(groupnumber * n_cycles));
    // Add dangling load time - this should not occur, just for consistency
    if(final_load) {
        dangling = loadlength - shiftlength;
    }
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    // Compute total duration, remove pointwaittime for last slew
    totaltime = totaltime + dangling - pointwaittime + tend;
    // show gyro-propagation messages
    int pointcycle = on_pointing + off_pointing + longslew;
    GCPMessages(off_pointing,2 * pointcycle,tend);
    // Return all the times needed in the observing mode modules

    return {totaltime,{on_inttime,off_inttime,on_pointing,off_pointing,loadlength,shiftlength,load_spacing,n_loadinterval,n_long_on,n_long_off,1,1,final_load,final_load,initlength,dangling},effchop_on,effchop_off,tscan};
}

double procedure HotColdRelaxTime {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double lo_freq = 978200.0; // LO frequency
    bool wbsused = true; // whether one of the WBS' is used
}{
    // Dead time given purely by the chopper
    double relaxtime = GetHotColdDeadTime(band,lo_freq);
    // Add WBS relaxation if this is used
    if(wbsused) {
        // Get the Bragg cell time constant
        double[] bragg = CalibrationReader("bragg_cell",["bragg_relaxtime"],band,lo_freq);
        double t_bragg = bragg[0];
        // Get the other involved temperatures
        double tsys = InterpolateTsys(band,lo_freq);
        {double,double} tloads = LoadTemperatures(band,lo_freq);
        // Compute involved level difference
        double hotlevel = tsys + tloads{0};
        double coldlevel = tsys + tloads{1};
        double difference = (hotlevel - coldlevel) / hotlevel;
        relaxtime = max(relaxtime,t_bragg * difference);
    }

    return relaxtime;
}

// Get minimum integration time per phase for fast-chop
int procedure GetMinChopPhaseLength {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] freq = CalibrationReader("chopfreq",["maxchopfreq"],band,lo_freq);
    double phaselength = 1000.0 / (2.0 * freq[0]);

    return iceil(phaselength);
}

//  LCU6Ha configuration into SAFE mode, procedure
procedure LCU6Ha_config_safe_proc_fm {
    string band = "7a"; // HIFI band
    double lo_freq = 1700.0 in [1700.0,1800.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

// Routines for calibration data handling
/////////////////////////////////////////////////////////////////
// Generic calibration file reader. This is called by all routines
// using calibration parameters. The same approach is used for fixed,
// band-dependent and LO frequency dependent quantities. Thus we
// can add more calibration information as we obtain it.
//
double[] procedure CalibrationReader {
    string topicname = "tsys"; // Name of entry in master file
    string[] objectnames = ["tsys_h"]; // Names of calibration objects to be read
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    // first step: read master file
    string calibfile = slookup("calibration_masterfile",topicname,"filename");
    int dep = ilookup("calibration_masterfile",topicname,"dependence");
    int readnum = length(objectnames);
    double[] retvalues = [];
    if(dep == 0) {
        // Quantity is constant
        // Read from single file by name
        for(int i = 1 .. readnum) {
            retvalues[i - 1] = dlookup(calibfile,objectnames[i - 1],"value");
        }
    } else {
        if(dep == 1) {
            // Quantity is band dependent
            // directly read from file looking up the band
            for(int k = 1 .. readnum) {
                retvalues[k - 1] = dlookup(calibfile,band,objectnames[k - 1]);
            }
        } else {
            // Quantity is band and frequency dependent
            // second step step: band look up, get name of responsible data file
            string actualfile = slookup(calibfile,band,"filename");
            // Now read interpolated value from the data base
            for(int j = 1 .. readnum) {
                retvalues[j - 1] = interpolate(actualfile,objectnames[j - 1],lo_freq);
            }
        }
    }

    return retvalues;
}

//Integration on Internal hot, block
block Hot_spectra_fm HIFI 3223 {
    string band = "1a";
    int integ_time = 4; //Total integration time in sec.: at least 2sec !
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //Rotate chopper: assume we come from M3
    Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_hot_ang");
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
}

// Initialisation of FPU, block with both MSA in use
// It is for cold context !
block Init_MSA_fm HIFI 3200 {
    string band = "1a"; // HIFI band
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
    string hbb_heater = "ON" in ["ON","OFF"]; //hot source on/off
}{
    //Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    if(hbb_heater == "ON") {
        result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,lo_freq);
        calibcurrent = result_d[0]{0};
    }
    //
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,0.0);
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //In case of band 6 or 7, bias have been set to 4mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    //Magnet are so far at maximum value. Now set to nominal
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
        Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
        delay(1);
    }
    //
    //Hifi_HIFI_non_periodic_hk_FCU ();
}

//HIFI-COP-X-IF-FBk-Cal
procedure IF_FBk_Cal_COP_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string[] hrs_mode = ["wb1","wb1"];
    int integ_time = 600;
    string backend = "both";
    string chopcase = "dbs" in ["dbs","csa","lsw"]; //chopper delta considered
}{
    //Switch-off LO
    LCU_switch_off_block_fm();
    //
    //For LSW
    string chop1 = "chop_M3";
    string chop2 = "chop_cold";
    if(chopcase == "dbs") {
        chop1 = "chop_M3right";
        chop2 = "chop_M3left";
    }
    if(chopcase == "csa") {
        chop1 = "chop_hot";
        chop2 = "chop_cold";
    }
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",[chop1,chop2],band,0.0);
    int[] res = [0,0];
    //
    Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
    //Use high biases
    result_d = ConfigurationReader("name_confilfpu",["bias_high_resistive_h","bias_high_resistive_v"],band,lo_freq);
    Mixerbias_block_fm(result_d[0]{0},result_d[1]{0});
    WBS_calib_fm(band);
    WBS_tune_proc_fm(band);
    HRS_config_block_fm(band,hrs_mode);
    HRS_tune_block_fm(band);
    //
    //Direct long integration
    res = Configure_Spectrometer_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    result_d = ConfigurationReader("name_confilfpu",[chop1,chop2],band,0.0);
    Spectro_slow_chop_block_fm(band,[result_d[0]{0},result_d[1]{0}],[integ_time * 2,1],backend);
    // 
}

// Interpolate coupling of the instrument for the selected frequency
double procedure InterpolateCoupling {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] eta = CalibrationReader("efficiency",["eta_mb"],band,lo_freq);

    return eta[0];
}

// WBS laser temperature control switched off, block
block Laser_T_check_off_fm HIFI 3705 {
}{
    Hifi_HIFI_WH_Laser_T_chck_off();
    Hifi_HIFI_WV_Laser_T_chck_off();
    delay(1);
}

// SFT: Init of all S/S, procedure
// This is for use in dummy (warm) context
procedure HIFI_SFT_proc {
    string band = "1a"; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string mixer_polarization = "H" in ["H","V","B"]; //Polarization: H, V or Both
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string chop_loop = "CLOSE"; //The chopper loop status
    int integ_time = 4; //Total integration time in sec.
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON  
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //
    //Init of instrument: depends on polarization
    //The chopper will look at a position depending on the test context
    {double,string}[] result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,lo_freq);
    //{double, string}[] result_d = ConfigurationReaderWarm("name_chopper",["chop_startup_warm"],
    //						     band,lo_freq);  
    double chop = result_d[0]{0};
    //
    if(mixer_polarization == "H") {
        Init_MSA_H_fm(band,chop_loop,lo_freq);
        //Init_MSA_fm_dummy(band,chop_loop,lo_freq);
    }
    if(mixer_polarization == "V") {
        Init_MSA_V_fm(band,chop_loop,lo_freq);
        //Init_MSA_fm_dummy(band,chop_loop,lo_freq);
    }
    if(mixer_polarization == "B") {
        Init_MSA_fm(band,chop_loop,lo_freq,"ON");
        //Init_MSA_fm_dummy(band,chop_loop,lo_freq);
    }
    //
    //Configure WBS laser according to user inputs. Delays are included
    //Maximum attenuation is used since it is what is set in the default config file
    //In fact laser should have been switched on previously for the 2 min. stabilization
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_config_w_laser_block_fm(band,laser_H,laser_V);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_config_max_att_block_fm(band,hrs_mode);
    }
    //
    //Init of LO: configuration. Delays are included
    Set_LO_Nominal_block_fm();
    LCU_switchon_proc_fm(band);
    //
    //Configure spectroscopy integration
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
}

//Generic procedure to launch engineering scan applied to chopper rotation, procedure
block Engineering_scan_for_diplexer_resp_block_ops HIFI 3951 {
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50]; // HIF_N_samples_1
    int samplesAfter = 1000 in [0,1000]; // HIF_N_samples_2
}{
    Start_block();
    //
    //H-diplexer - forward motion - read diplexer current
    Hifi_HIFI_engineering_scan(milliSecSample,0x8c50,0xfff,0xfff,0xcc100000,samplesBefore,samplesAfter);
    //Compute delay
    int nb_HK = 1;
    //For this TC, the 2 last HK fields are blanked out
    int millisecondsUsed = 1000 + 10 + milliSecSample * nb_HK * (samplesBefore + samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //H-diplexer - reverse motion - read diplexer current
    Hifi_HIFI_engineering_scan(milliSecSample,0x8c50,0xfff,0xfff,0xcc100fff,samplesBefore,samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //H-diplexer - forward motion - read diplexer voltage
    Hifi_HIFI_engineering_scan(milliSecSample,0x8c51,0xfff,0xfff,0xcc100000,samplesBefore,samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //H-diplexer - reverse motion - read diplexer voltage
    Hifi_HIFI_engineering_scan(milliSecSample,0x8c51,0xfff,0xfff,0xcc100fff,samplesBefore,samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //
    //V-diplexer - forward motion - read diplexer current
    Hifi_HIFI_engineering_scan(milliSecSample,0x8d50,0xfff,0xfff,0xcd100000,samplesBefore,samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //V-diplexer - reverse motion - read diplexer current
    Hifi_HIFI_engineering_scan(milliSecSample,0x8d50,0xfff,0xfff,0xcd100fff,samplesBefore,samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //V-diplexer - forward motion - read diplexer voltage
    Hifi_HIFI_engineering_scan(milliSecSample,0x8d51,0xfff,0xfff,0xcd100000,samplesBefore,samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //V-diplexer - reverse motion - read diplexer voltage
    Hifi_HIFI_engineering_scan(milliSecSample,0x8d51,0xfff,0xfff,0xcd100fff,samplesBefore,samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //
}

// FPU Standby with HBB OFF, block
block Band0_hbb_off_block_ops HIFI 7299 {
    string band = "0"; // HIFI band
    string chop_loop = "CLOSE"; // Chopper Loop status
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //  
    double calibcurrent = result_d[7]{0};
    //
    result_d = ConfigurationReader("name_confilfpu",["bias_standby_h","diplexer_standby_h","bias_standby_v","diplexer_standby_v","diplex_h_ctrl_mode","diplex_v_ctrl_mode","chop_M3right"],band,0.0);
    //
    double bias_H = result_d[0]{0};
    double diplex_H = result_d[1]{0};
    double bias_V = result_d[2]{0};
    double diplex_V = result_d[3]{0};
    int diplex_h_ctrl_mode = iround(result_d[4]{0});
    int diplex_v_ctrl_mode = iround(result_d[5]{0});
    double chopper = result_d[6]{0};
    //
    //Retrieve magnets.
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_standby_h","magnet_standby_v"],band,0.0);
        double magnetcurrent_H = result_d[0]{0};
        double magnetcurrent_V = result_d[1]{0};
    }
    //
    //Upconverter: should be kept ON at this stage. No particular action.
    //
    if(prime_or_redundant == "Prime") {
        Hifi_HIFI_P_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    } else {
        Hifi_HIFI_R_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    }
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    Hifi_HIFI_non_periodic_hk_FCU();
    //
    mois_tmcheck("Check that parameter HF_APR_CS_C is set to " + calibcurrent + " mA");
    mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to " + chop_loop);
    mois_tmcheck("Check that parameter HF_DPR_CHSINE_S is set to " + chop_sine_s);
}

bool procedure IntIsContained {
    int x = 1; // search string
    int[] lot = [0]; // array to be searched
}{
    int nlen = length(lot);
    bool found = false;
    for(int i = 0 .. nlen - 1) {
        if(x == lot[i]) {
            found = true;
        }
    }

    return found;
}

//Generic procedure to perform fast chopper scan using the adequate instrument side
procedure HIFI_Chopper_scan_fast_proc_fm {
    int milliSecSample = 3; // interval between samples
    double targetAngle = 0.0; //Target chopper voltage
    int samplesBefore = 30 in [0,50]; // HIF_N_samples_1
    int samplesAfter = 1000 in [0,1000]; // HIF_N_samples_2
}{
    //check prime or redundant keyword
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant"],"0",0.0);
    if(result_d[0]{1} == "prime") {
        Hifi_HIFI_P_Chopper_scan_fast(milliSecSample,targetAngle,samplesBefore,samplesAfter);
    } else {
        Hifi_HIFI_R_Chopper_scan_fast(milliSecSample,targetAngle,samplesBefore,samplesAfter);
    }
    //
}

//Notify PDU status OFF, block
block HIFI_notify_PDU_status_off_block_fm HIFI 3654 {
    string status_FCU = "OFF" in ["ON","OFF"]; //Status of FCU
    string status_LCU = "OFF" in ["ON","OFF"]; //Status of LCU
    string status_WBSV = "OFF" in ["ON","OFF"]; //Status of WBSV
    string status_WBSH = "OFF" in ["ON","OFF"]; //Status of WBSH
    string status_HRSV = "OFF" in ["ON","OFF"]; //Status of HRSV
    string status_HRSH = "OFF" in ["ON","OFF"]; //Status of HRSH
}{
    Start_block_no_hk_request();
    Hifi_HIFI_notify_PDU_status(status_FCU,status_LCU,status_WBSV,status_WBSH,status_HRSV,status_HRSH);
    delay(1);
}

// perform peak-up correction
block HifiPeakupCorrection HIFI 6822 {
}{
    // Perform correction
    Hifi_HIFI_correction_AOCS($BBID);
    delay(1);
}

/////////////////////////////////////////////////////////////////////////////
// The actual commanding procedures
// total power
procedure HIFI_Spectr_tp_proc_aot {
    int n_int = 1; // Integration time counter
    int data_time = 4; // Integration time between two data readouts
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    // Call command
    Hifi_HIFI_Spectr_total_power($BBID);
    delay(n_int * data_time);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

//HIFI-COP-1.2-IF_FT
procedure IF_FT_COP_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b","8"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_comment("Start of HIFI IF Functional Test for band " + band);
    mois_comment("Please ensure that instrument was switched on with the " + prime_or_redundant + " unit");
    //General parameters in use
    int integ_time = 4;
    string backend = "both";
    string hbb_heater = "ON";
    //hot source on/off
    string chopper_loop = "CLOSE";
    //
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    mois_step("Init of FPU");
    Init_MSA_ops(band,chopper_loop,lo_freq,result[0]{0},hbb_heater,prime_or_redundant);
    mois_tmcheck("Check content of ANDs FCU_H_device, FCU_V_device, FCU_PR_power and FPU_common with HIFI expert");
    //
    //Set mixer bias to 5mV
    mois_step("Turn on shot noise for band 5 mixers");
    result = ConfigurationReader("name_confilfpu",["bias_low_resistive_h","bias_low_resistive_v"],band,0.0);
    double bias_low_h = result[0]{0};
    double bias_low_v = result[1]{0};
    //Set magnets to 0
    Set_Magnet_current_block_fm(0.0,0.0);
    mois_tmcheck("Check that parameters HF_AH1_MXMG_C and HF_AV1_MXMG_C are both set to 0 mA");
    //
    Mixerbias(bias_low_h,bias_low_v);
    mois_tmcheck("Check that parameters HF_AH1_MXBIAS_V and HF_AV1_MXBIAS_V are set to " + bias_low_h + " and " + bias_low_v + " mV respectively");
    //
    mois_step("WBS tuning with Laser 2");
    string laser_H = "Laser2";
    string laser_V = "Laser2";
    WBS_config_w_laser_block_fm(band,laser_H,laser_V);
    mois_tmcheck("Check that parameters HWH_Laser2_S and HWV_Laser2_S are ON");
    WBS_tune_proc_fm(band);
    HRS_tune_block_fm(band);
    //To check final attenuator settings
    Configure_Spectrometer_proc_fm(band,integ_time,["wb1","wb1"],backend);
    Spectro_total_power_block_fm(band,[integ_time,1],backend);
    //
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of DBS-raster cross observing mode
{int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} procedure DBSCross_post_timing {
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = {4,10,4,21,1,1800,0,10,1,1,1,50,0}; // full timing parameter list  
    int[] telescopetimes = [300,180,20,0,21,0,2,10];
    int npoints = 10; // Number of points per row
    int n_chop = 2; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800; // load period = f(band,lo_freq,eff_resolution{1})
    bool fastchop = false; // whether fast-chop is used instead of slow-chop
}{
    // Get all values from the pre_timing section
    int inttime = pre_timing{0};
    int pointing = pre_timing{1};
    int readouttime = pre_timing{2};
    int loadlength = pre_timing{3};
    int jitterdead = pre_timing{4};
    int load_spacing = pre_timing{5};
    int n_load = pre_timing{6};
    int n_loadinterval = pre_timing{7};
    int n_seq = pre_timing{8};
    int n_scans = pre_timing{9};
    int scansize = pre_timing{10};
    int initlength = pre_timing{11};
    int dangling = pre_timing{12};
    // Get all values from the telescope section  
    int telinit = telescopetimes[1];
    // Initial slew time
    int longslew = telescopetimes[4];
    // Actual slew time for load slew
    int tend = telescopetimes[5];
    // Final deceleration time
    ///////////////////////
    // Long computation for scansize > 1 to obtain all slew durations
    {int,int,int} sumslewtimes = GetAllCrossSlewTimes(telescopetimes,scansize,n_cycles);
    int tinscandead = sumslewtimes{0};
    int toutscandead = sumslewtimes{1};
    int shortmove = sumslewtimes{2};
    // Total number of scans
    int n_tot = n_scans * n_cycles;
    // Compute total duration of measurement and average scan length
    int totalscantime = n_tot * (2 * pointing * scansize) + tinscandead;
    // approximate scan time for load comparison
    int scan_time = iceil(double(totalscantime) / double(2 * n_tot));
    if(load_spacing > 2 * scan_time) {
        n_seq = n_chop;
        pointing = inttime + jitterdead;
        bool end_load = false;
    } else {
        // It could happen that the slew extends the scan too much - catch
        if(scansize > 1) {
            SError("Number of points in one scan too large for load period.");
        }
        n_load = n_load + 1;
        n_seq = n_chop / n_load;
        // adjust pointing time to include load measurements
        int loadappend = imax(loadlength - shortmove,0);
        end_load = true;
        // Computation for slow-chop or fast-chop
        if(fastchop) {
            inttime = n_seq * n_load * readouttime;
        } else {
            inttime = 2 * n_seq * n_load * readouttime;
        }
        pointing = inttime + loadappend + (n_load - 1) * loadlength + jitterdead;
    }
    totalscantime = n_tot * (2 * pointing * scansize) + tinscandead + toutscandead;
    scan_time = iceil(double(totalscantime) / double(2 * n_tot));
    // compute the load interval in case of short scan_time
    n_loadinterval = imax((load_interval - loadlength + longslew) / (2 * scan_time),1);
    // Special treatment for nodding_IN_raster due to limitations in API
    // Split into loads per point or per multiple points
    if(scansize == 1) {
        int nodtime = tinscandead / n_tot;
        if(n_loadinterval > n_cycles) {
            n_loadinterval = n_cycles * (n_loadinterval / n_cycles);
            n_loadinterval = imin(n_loadinterval,n_tot);
            // Translate load waiting time into a hold after the point
            int holdlength = imax(loadlength - nodtime,0);
            int loadadded = holdlength;
            int n_long = n_tot / n_loadinterval;
        } else {
            // Nodding in raster with loads per point
            holdlength = 0;
            loadadded = longslew - nodtime;
            // compensate counter reset
            int dangling_period = n_cycles % n_loadinterval;
            while((dangling_period + n_loadinterval) * 2 * scan_time > load_interval - loadlength + longslew) {
                n_loadinterval = n_loadinterval - 1;
                dangling_period = n_cycles % n_loadinterval;
            }
            // Consistency check
            if(n_loadinterval < 1) {
                CError("Too short load period computed.");
            }
            n_long = n_scans * (n_cycles / n_loadinterval);
        }
    } else {
        // Treatment for nodding_OF_raster
        int minnod = GetMinLoadNod(telescopetimes,scansize,n_cycles,n_loadinterval);
        holdlength = imax(loadlength - minnod,0);
        loadadded = holdlength;
        n_long = n_tot / n_loadinterval;
    }
    // Compute total duration of measurement, correct for load nods
    totalscantime = n_tot * (2 * pointing * scansize) + tinscandead + n_long * loadadded;
    // Average dead and scan time for drift estimate
    double tscan = double(totalscantime) / double(n_tot);
    double tdead = tscan - double(2 * inttime * scansize);
    // Count integration times of other points of one nod as dead time
    // Other points in the second nod are excluded from the scan
    double othertime = double((scansize - 1) * inttime);
    tdead = tdead + othertime;
    // Reduce scan time by the other points in the second nod phase
    tscan = tscan - othertime;
    // Determine need for final load measurement
    double rest = double(n_tot % n_loadinterval) + 0.5;
    bool final_load = rest > 0.5001 * double(n_loadinterval);
    // Compute total duration
    // The initial time is no longer contained in the total time  
    // int totaltime=imax(initlength,telinit);
    int totaltime = totalscantime + toutscandead;
    // Add dangling load time if not included in pointing
    // they are mutually exclusive, otherwise the readoutdelay applies
    if(final_load) {
        dangling = loadlength;
    }
    if(end_load) {
        dangling = loadlength - loadappend;
    }
    int closelength = duration(HIFICloseObs());
    dangling = imax(dangling + closelength - tend,0);
    totaltime = totaltime + dangling + tend;
    // show gyro-propagation messages
    // no gyro-propagation for custom_map
    GCPMessages(0,totalscantime / n_cycles,tend);
    // Return all the times needed in the observing mode modules

    return {totaltime,{inttime,pointing,readouttime,loadlength,holdlength,load_spacing,n_load,n_loadinterval,n_seq,n_scans,scansize,initlength,dangling},final_load,tscan,tdead};
}

// Single integration with no change of setups, procedure
procedure Total_power_integration_proc {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
}{
    error("Procedure Total_power_integration_proc is not used anymore.");
}

// IV curve, block
block IVcurve_defluxed_fm HIFI 3212 {
    string band = "1a";
}{
    //Start_block() ;   
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["bias_min_h","bias_max_h","bias_steps_h","bias_min_v","bias_max_v","bias_steps_v"],band,0.0);
    //H polar
    double bias_min_h = result_d[0]{0};
    double bias_max_h = result_d[1]{0};
    int steps_h = iround(result_d[2]{0});
    //V polar
    double bias_min_v = result_d[3]{0};
    double bias_max_v = result_d[4]{0};
    int steps_v = iround(result_d[5]{0});
    //Bias to set at end of IVC
    //Need a representative frequency: take keyfreq
    double[] result = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = result[0];
    //
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v","norm_magn_h","norm_magn_v"],band,lo_freq);
    double bias_h = result_d[0]{0};
    double bias_v = result_d[1]{0};
    //Fetch magnets only if band is not band6
    double magnetcurrent_h = 0.0;
    double magnetcurrent_v = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        magnetcurrent_h = result_d[2]{0};
        magnetcurrent_v = result_d[3]{0};
    }
    //The IVCurve is done on the smallest range and the finest step
    double bias_min = max(bias_min_h,bias_min_v);
    double bias_max = min(bias_max_h,bias_max_v);
    int steps = iround(max(double(steps_h),double(steps_v)));
    //
    //First set magnets to max.
    double magnet_current_max_h = 0.0;
    double magnet_current_max_v = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,0.0);
        magnet_current_max_h = result_d[0]{0};
        magnet_current_max_v = result_d[1]{0};
    }
    Hifi_HIFI_CH1_MX_MG_C($BBID,magnet_current_max_h);
    Hifi_HIFI_CV1_MX_MG_C($BBID,magnet_current_max_v);
    delay(1);
    //Perform IV curve
    IVcurve(band,bias_min,bias_max,steps,magnetcurrent_h,magnetcurrent_v,bias_h,bias_v);
}

// building block to initialize load calibration measurement
// and compute main parameters
{int,int,bool} block HIFICalInit HIFI 6008 {
    string band = "4a"; // HIFI band (needed to estimate stabilization)
    double lo_freq = 978200.0; // LO frequency
    double deltanu = 1.0; // minimum effective resolution of the calibrated data
    int data_time = 4; // time between subsequent data readouts
}{
    // The minimum integration time is given by data_time
    // However, we introduce an upper limit of 6s here (covers 24bit mode)
    int used_datatime = imin(data_time,6);
    // Check whether frequent retuning is needed
    double[] allan = CalibrationReader("loaddiff_stability",["instable"],band,lo_freq);
    bool retuning = allan[0] > 0.0;
    // Compute integration time
    int min_int_time = LoadIntegrationTime(band,lo_freq,deltanu);
    if(retuning) {
        int n_inttime = 2 * iceil(0.5 * double(min_int_time) / double(used_datatime));
    } else {
        n_inttime = 2 * iceil(double(min_int_time) / double(used_datatime));
    }
    // return parameters

    return {used_datatime,n_inttime,retuning};
}

//  LCU switch-off, block
block LCU_switch_off_block_aot HIFI 6631 {
}{
    {double,string}[] result = ConfigurationReader("name_delays",["switch_off_delay"],"0",0.0);
    int switch_off_delay = iround(result[0]{0});
    //
    //Send command: this is the effective switch-off
    //Hifi_HIFI_Conf_nom_LCU_ch0($BBID);  //Removed to fix SPR-2522
    //
    delay(switch_off_delay);
    //
    //Set heater to their stby value: should not depend on band
    HL_heater_proc_aot("1a","stby");
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
double procedure PositionSwitch_deadtimes {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,5]; // data dump interval limited by the data rates
    int n_int = 3 in [2,1800]; // number of data dumps for integration per phase
    double tdead = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Compute parameters for the instrument timing
    {double,double} tinst = GetInstDeadSlowChop(data_time,n_int,"tp",band,lo_freq,backendreadoutparms);
    // total dead time in one cycle
    double tinst_dead = double(data_time * n_int) - tinst{0};
    // Total dead time per cycle
    double tdead_tot = tdead + 2.0 * tinst_dead;

    return tdead_tot;
}

//Set HIFI to standby I - lasers are forced to Off. HBB stays ON
obs HifiEngSetIntoStandby_I {
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(HifiIntoStandby_I());
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // ON integration
            HifiIntoStandby_I();
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The procedures/blocks
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// HRS complete configuration, block
// Both polarizations are treated
block HRS_config_block_fm HIFI 3632 {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    //Start_block();
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double hrsH_ATT_U1 = result[1]{0};
    double hrsH_ATT_L1 = result[2]{0};
    double hrsH_ATT_U2 = result[3]{0};
    double hrsH_ATT_L2 = result[4]{0};
    double hrsH_ATT_U3 = result[5]{0};
    double hrsH_ATT_L3 = result[6]{0};
    double hrsH_ATT_U4 = result[7]{0};
    double hrsH_ATT_L4 = result[8]{0};
    double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double hrsV_ATT_U1 = result[1]{0};
    double hrsV_ATT_L1 = result[2]{0};
    double hrsV_ATT_U2 = result[3]{0};
    double hrsV_ATT_L2 = result[4]{0};
    double hrsV_ATT_U3 = result[5]{0};
    double hrsV_ATT_L3 = result[6]{0};
    double hrsV_ATT_U4 = result[7]{0};
    double hrsV_ATT_L4 = result[8]{0};
    double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //Convert IF frequencies into A and M parameters
    //Truncate wb keyword:
    string[] output_hrs_mode = GetHrsMode_proc_fm(hrs_mode);
    string hrs_mode_h = output_hrs_mode[0];
    string hrs_mode_v = output_hrs_mode[1];
    //
    int[] a_m_parameter = ComputeA_M_parameters([hrs_mode_h,hrs_mode_v],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_ATT_U1,hrsH_ATT_L1,hrsH_ATT_U2,hrsH_ATT_L2,hrsH_ATT_U3,hrsH_ATT_L3,hrsH_ATT_U4,hrsH_ATT_L4,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
    // 
    //delay(hrs_config_delay);
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsV_ATT_U1,hrsV_ATT_L1,hrsV_ATT_U2,hrsV_ATT_L2,hrsV_ATT_U3,hrsV_ATT_L3,hrsV_ATT_U4,hrsV_ATT_L4,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
    // 
    delay(hrs_config_delay);
    ////////////////////////////////////////////////////////////////////
    //Now Configure blocks
    //H-polar
    result = ConfigurationReader(hrs_filename_h,["hrh_block_1","hrh_block_2","hrh_block_3","hrh_block_4","hrh_block_5","hrh_block_6","hrh_block_7","hrh_block_8"],band,0.0);
    string hrh_block_1 = result[0]{1};
    string hrh_block_2 = result[1]{1};
    string hrh_block_3 = result[2]{1};
    string hrh_block_4 = result[3]{1};
    string hrh_block_5 = result[4]{1};
    string hrh_block_6 = result[5]{1};
    string hrh_block_7 = result[6]{1};
    string hrh_block_8 = result[7]{1};
    //
    Hifi_HIFI_Config_HRS_H_blocks($BBID,hrh_block_1,hrh_block_2,hrh_block_3,hrh_block_4,hrh_block_5,hrh_block_6,hrh_block_7,hrh_block_8);
    //delay(hrs_config_delay);
    //
    //V-polar
    result = ConfigurationReader(hrs_filename_v,["hrv_block_1","hrv_block_2","hrv_block_3","hrv_block_4","hrv_block_5","hrv_block_6","hrv_block_7","hrv_block_8"],band,0.0);
    string hrv_block_1 = result[0]{1};
    string hrv_block_2 = result[1]{1};
    string hrv_block_3 = result[2]{1};
    string hrv_block_4 = result[3]{1};
    string hrv_block_5 = result[4]{1};
    string hrv_block_6 = result[5]{1};
    string hrv_block_7 = result[6]{1};
    string hrv_block_8 = result[7]{1};
    //
    Hifi_HIFI_Config_HRS_V_blocks($BBID,hrv_block_1,hrv_block_2,hrv_block_3,hrv_block_4,hrv_block_5,hrv_block_6,hrv_block_7,hrv_block_8);
    //
    //Wait delay to allow all setting to be configured
    delay(hrs_config_delay);
}

// Needs the chopper in open-loop mode !!
block Chopper_closed_loop_parameter_check_block_fm HIFI 3695 {
}{
    Start_block();
    //Move chopper to 0V
    double targetAngle = 0.0;
    HIFI_CPR_Chopper_Rot_proc_fm(targetAngle);
    Hifi_HIFI_non_periodic_hk_FCU();
    //To get sent voltage
    delay(1);
    //
    //Go to -7.09V and monitor short term stabilisation
    int milliSecSample = 3;
    // interval between samples
    int samplesBefore = 50;
    int samplesAfter = 1000;
    targetAngle = -7.09;
    Engineering_scan_for_closed_loop_scan(targetAngle,milliSecSample,samplesBefore,samplesAfter);
    //
    //Monitor chopper position while staying at -7.09V
    milliSecSample = 10;
    // interval between samples
    //This special procedure does not change prime angles into red angles
    Engineering_scan_for_closed_loop_scan(targetAngle,milliSecSample,samplesBefore,samplesAfter);
    //
    //Move chopper to 0V
    targetAngle = 0.0;
    HIFI_CPR_Chopper_Rot_proc_fm(targetAngle);
    Hifi_HIFI_non_periodic_hk_FCU();
    //To get sent voltage
    delay(1);
    //
    //Move to -0.37 and monitor short term stabilisation
    milliSecSample = 3;
    // interval between samples
    targetAngle = -0.37;
    //This special procedure does not change prime angles into red angles
    Engineering_scan_for_closed_loop_scan(targetAngle,milliSecSample,samplesBefore,samplesAfter);
    //
    //Move back to rest position: this one depends on prime/red
    {double,string}[] result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],"0",0.0);
    targetAngle = result_d[0]{0};
    HIFI_CPR_Chopper_Rot_proc_fm(targetAngle);
    Hifi_HIFI_non_periodic_hk_FCU();
    //To get sent voltage
    delay(1);
}

// Compute effective fluctuation bandwidth determining the
// radiometric noise from the selected resolution
{double,double} procedure EffectiveResolution {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Selected min./max. goal resolution of calibrated data
    bool resolutionMhz = true; //whether resolution is given in MHz or in km/s
    bool wbs1used = true; // WBS1 to be used
    bool wbs2used = true; // WBS2 to be used
    {bool,int} hrs1 = {true,1}; // {HRS1 to be used, resolution}
    {bool,int} hrs2 = {true,1}; // {HRS2 to be used, resolution}
}{
    // translate to Mhz is required
    double lightspeed = 300000.0;
    // km/s
    if(resolutionMhz) {
        double resol_hi = effResolution{0};
        double resol_lo = effResolution{1};
    } else {
        resol_hi = effResolution{0} * lo_freq / lightspeed;
        resol_lo = effResolution{1} * lo_freq / lightspeed;
    }
    // compute fluctuation bandwidth from selected resolution
    // 1. physical resolutions used
    // build up list of available resolutions
    double[] physres_list = [0.0];
    double[] fluctratio_list = [0.0];
    bool[] ishrs_list = [false];
    int n_resol = 0;
    // WBS
    if(wbs1used || wbs2used) {
        double[] res = GetBackendResolution(band,lo_freq,-1);
        physres_list[n_resol] = res[0];
        fluctratio_list[n_resol] = res[1];
        ishrs_list[n_resol] = false;
        n_resol = n_resol + 1;
    }
    // resolution order of HRS's
    if(hrs1{0} && hrs2{0}) {
        int lores = imax(hrs1{1},hrs2{1});
        int hires = imin(hrs1{1},hrs2{1});
        if(hires != lores) {
            res = GetBackendResolution(band,lo_freq,lores);
            physres_list[n_resol] = res[0];
            fluctratio_list[n_resol] = res[1];
            ishrs_list[n_resol] = true;
            n_resol = n_resol + 1;
            res = GetBackendResolution(band,lo_freq,hires);
            physres_list[n_resol] = res[0];
            fluctratio_list[n_resol] = res[1];
            ishrs_list[n_resol] = true;
            n_resol = n_resol + 1;
        } else {
            res = GetBackendResolution(band,lo_freq,lores);
            physres_list[n_resol] = res[0];
            fluctratio_list[n_resol] = res[1];
            ishrs_list[n_resol] = true;
            n_resol = n_resol + 1;
        }
    } else {
        if(hrs1{0}) {
            res = GetBackendResolution(band,lo_freq,hrs1{1});
            physres_list[n_resol] = res[0];
            fluctratio_list[n_resol] = res[1];
            ishrs_list[n_resol] = true;
            n_resol = n_resol + 1;
        }
        if(hrs2{0}) {
            res = GetBackendResolution(band,lo_freq,hrs2{1});
            physres_list[n_resol] = res[0];
            fluctratio_list[n_resol] = res[1];
            ishrs_list[n_resol] = true;
            n_resol = n_resol + 1;
        }
    }
    // Compare with desired resolutions
    double physres_lo = physres_list[0];
    double fluctratio_lo = fluctratio_list[0];
    bool ishrs_lo = ishrs_list[0];
    double physres_hi = physres_list[0];
    double fluctratio_hi = fluctratio_list[0];
    bool ishrs_hi = ishrs_list[0];
    // go from lowest resolution to highest 
    // get parameters of backend just covering the goal
    for(int iresol = 1 .. n_resol - 1) {
        if(resol_hi < physres_list[iresol - 1]) {
            physres_hi = physres_list[iresol];
            fluctratio_hi = fluctratio_list[iresol];
            ishrs_hi = ishrs_list[iresol];
        }
        if(resol_lo < physres_list[iresol - 1]) {
            physres_lo = physres_list[iresol];
            fluctratio_lo = fluctratio_list[iresol];
            ishrs_lo = ishrs_list[iresol];
        }
    }
    // Consistency check
    if(resol_hi < physres_list[n_resol - 1]) {
        IError("The requested goal resolution cannot be achieved with the" + " selected backend settings. Increase the goal resolution" + " minimum or change the spectrometer settings.");
    }
    // Translate into fluctuation bandwidths
    double effresol_lo = resol_lo + physres_lo * (fluctratio_lo - 1.0);
    double effresol_hi = resol_hi + physres_hi * (fluctratio_hi - 1.0);
    // correct for finite HRS efficiency - reduce noise bandwidth
    double hrseffic = GetHrsEfficiency(band,lo_freq);
    if(ishrs_hi) {
        effresol_hi = effresol_hi * (hrseffic * hrseffic);
    }
    if(ishrs_lo) {
        effresol_lo = effresol_lo * (hrseffic * hrseffic);
    }
    // return result

    return {effresol_hi,effresol_lo};
}

// Produce array of LO frequencies to be used in frequency clusters
double[] procedure GetClusterFrequencies {
    double lo_freq = 978200.0; // LO frequency in MHz
    int groupsize = 3; // Number of frequencies in a cluster
    double freqstep = 120.0; // step size in a frequency cluster
}{
    // Use the same order as within spectral scan groups
    int[][] grouporder = GetFrequencyGroupSteps(groupsize);
    double[] freqs = [];
    for(int i = 0 .. groupsize - 1) {
        freqs[i] = lo_freq + freqstep * double(grouporder[1][i] - groupsize / 2);
    }

    return freqs;
}

// LO SFT, following procedure of MPI, procedure
// Pre-defined frequencies and Vd2
// It is used for LOU dummy here
procedure LO_SFT_proc_fm {
    string band = "ALL" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b","ALL"]; // HIFI band: ALL or dedicated band
}{
    //For the chosen band, or all band (if option ALL)
    //	1. switch on band (with safe d2_v)
    //	2. configure with dedicated d2_v
    string[] band_list = ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"];
    int total = 14;
    if(band != "ALL") {
        band_list = [band];
        total = 1;
    }
    //
    double lo_freq = 0.0;
    double drain2_v = 0.0;
    for(int i = 0 .. total - 1) {
        double[] cresult_d = CalibrationReader("name_keyfreq",["keyfreq","key_d2v_P","key_d2v_R","key_d2v_dummy","keyfreq_dummy","keyfreqwarm"],band_list[i],0.0);
        lo_freq = cresult_d[0];
        //applies to cold LO
        //lo_freq = cresult_d[4];	//applies to dummy LO
        //lo_freq = cresult_d[5];	//applies to warm LO
        //Switch on with safe Vd2
        LCU_switchon_proc_fm(band_list[i]);
        //LO freq and Vd2 to use is embedded in the proc
        //Wait total of 20 sec.
        delay(20);
        //Check what d2_v to use depending on test circumstances
        drain2_v = cresult_d[1];
        //Value for prime case, and fm H/W
        //
        {double,string}[] result = ConfigurationReader("name_chopper",["prime_or_redundant","fm_or_dummy"],"0",0.0);
        //
        if(result[0]{1} == "redundant") {
            drain2_v = cresult_d[2];
        }
        if(result[1]{1} == "dummy") {
            drain2_v = cresult_d[3];
            lo_freq = cresult_d[4];
        }
        //
        LCU_config_nominal_w_D2_proc_fm(band_list[i],lo_freq,drain2_v);
    }
    //Switch off LO at end of test only if ALL option selected
    if(band == "ALL") {
        LCU_switch_off_block_fm();
    }
}

//Readback of LCU Memory Patch, block
block LcuMemoryPatchReadback_ops HIFI 7903 {
    string section = "P" in ["P","R"];
}{
    StartBlock_ops();
    //
    //{int, int[]} [] runs = LcuGetMemoryRuns_ops( section);
    {int,int[]}[] runs = LcuGetMemoryRuns(section,1);
    int runcount = length(runs);
    if(runcount != 0) {
        for(int i = 0 .. runcount - 1) {
            int count = length(runs[i]{1});
            Hifi_HIFI_dump_memory("LCU",runs[i]{0},count);
            //	delay( iceil( double( count ) *.003 ) ); // 3 msec per word readout
            //	Workaround
            delay(2 + iceil(double(count) * 0.0030));
            // 3 msec per word readout
        }
        //Complement the number of TCs sent to reach the fixed TC pattern needed for TPF
        int nb_TC_needed = 50;
        int remaining_TC = nb_TC_needed - runcount;
        mois_comment("The following " + remaining_TC + " TCs are dummy repetition of the first memory dump command");
        //
        for(int ii = 1 .. remaining_TC) {
            Hifi_HIFI_dump_memory("LCU",runs[0]{0},length(runs[0]{1}));
            delay(2 + iceil(double(count) * 0.0030));
            // 3 msec per word readout
        }
    }
}

// Very fast sampling stability measurement, procedure
// Uses only the HRS in wb mode
procedure Stability_fast_proc_fm {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int n = 100; //Number of samples to be measured
    double[] hrs_subband = [5.0,5.0,5.0,5.0]; //Positions in IF of HRS sub-bands
    double sampling_rate = 2.0 in [1.0,6.0]; //Sampling rate: 2 (2 HRS-H + 2 HRS-V), 3 (HRS-H + HRS-V),  4 (2 HRS-H or 2 HRS-V) or 6 (1 HRS-H or 1 HRS-V) Hz
    string hrs_polarization = "H" in ["H","V","B"]; //HRS polarization: selection works only for 4 and 8 Hz
}{
    //Configure HRS: regardless of selected bands
    HRS_config_resol_block_fm(band,["wb1","wb1"]);
    HRS_config_att_lo_w_lo_input_block_fm(band,["wb1","wb1"],hrs_subband);
    //Tune backend on cold load
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_cold_ang");
    //Look at CBB    
    HRS_tune_block_fm(band);
    //The following will configure spectroscopy and start total power integration
    Stability_fast_block_fm(band,n,sampling_rate,hrs_polarization);
    //
}

// Check whether the input frequencies are allowed
procedure CheckLOFrequencies {
    string band = "4a"; // HIFI band
    double lo_freq_low = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
}{
    {double,double} bandlimits = GetBandLimits(band);
    if(lo_freq_low < bandlimits{0} || lo_freq_up < lo_freq_low || lo_freq_up > bandlimits{1}) {
        IError("Frequencies fall outside of the selected LO band.");
    }
}

/////////////////////////////////////////////////////////////////////////////
// The tuning blocks 
//
// Initial tuning of the instrument
procedure TuneHIFI {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1parms = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets,subbands used}
    {bool,int,double[],bool[]} hrs2parms = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets,subbands used}
    bool wbs1parms = true; // WBS1 parameter =used
    bool wbs2parms = true; // WBS2 parameter =used
    string level = "normal"; // Name of target level
}{
    // Switch to high HK rate
    HIFISetHK("fast",true);
    ConfigureFPU(band,lo_freq,true);
    ConfigureBackend(band,lo_freq,hrs1parms,hrs2parms);
    HIFITune(band,lo_freq,hrs1parms{0},hrs2parms{0},wbs1parms,wbs2parms,level);
    // Switch to standard HK rate
    HIFISetHK("normal",true);
}

////////////////////////////////////
// Configuration routines
///////////////////////////////////
//Generic procedure to configure the FPU using the adequate instrument side
procedure HIFI_Configure_FCU_proc_aot {
    int band_nb = 0; // HF_CPR_MXBAND
    int diplex_h_ctrl_mode = 227; // HF_CV1_DPFPP1
    double volt_H_FIF_1 = 0.075; // HF_CH2_FIF1_Drain_V
    double curr_H_FIF_1 = 0.5; // HF_CH2_FIF1_Drain_C
    double volt_H_FIF_2 = 0.075; // HF_CH2_FIF2_Drain_V
    double curr_H_FIF_2 = 0.5; // HF_CH2_FIF2_Drain_C
    double volt_H_SIF_1 = 0.075; // HF_CH2_SIF1_Drain_V
    double curr_H_SIF_1 = 0.5; // HF_CH2_SIF1_Drain_C
    double volt_H_SIF_2 = 0.075; // HF_CH2_SIF2_Drain_V
    double curr_H_SIF_2 = 0.5; // HF_CH2_SIF2_Drain_C
    double volt_H_SIF_3 = 0.075; // HF_CH2_SIF3_Drain_V
    double curr_H_SIF_3 = 0.5; // HF_CH2_SIF3_Drain_C
    int diplex_v_ctrl_mode = 227; // HF_CV1_DPFPP1
    double volt_V_FIF_1 = 0.075; // HF_CV2_FIF1_Drain_V
    double curr_V_FIF_1 = 0.5; // HF_CV2_FIF1_Drain_C
    double volt_V_FIF_2 = 0.075; // HF_CV2_FIF2_Drain_V
    double curr_V_FIF_2 = 0.5; // HF_CV2_FIF2_Drain_C
    double volt_V_SIF_1 = 0.075; // HF_CV2_SIF1_Drain_V
    double curr_V_SIF_1 = 0.5; // HF_CV2_SIF1_Drain_C
    double volt_V_SIF_2 = 0.075; // HF_CV2_SIF2_Drain_V
    double curr_V_SIF_2 = 0.5; // HF_CV2_SIF2_Drain_C
    double volt_V_SIF_3 = 0.075; // HF_CV2_SIF3_Drain_V
    double curr_V_SIF_3 = 0.5; // HF_CV2_SIF3_Drain_C
    string chop_sine_s = "ON" in ["OFF","ON"]; // HF_CPR_CH_SINE_S
    string chop_loop = "CLOSE" in ["CLOSE","OPEN"]; // HF_CPR_CH_LOOP_S
    int chop_G1 = 0; // HF_CPR_CHFPG1
    int chop_G2 = 0; // HF_CPR_CHFPG2
    int chop_Z1 = 0; // HF_CPR_CHFPZ1
    int chop_Z2 = 0; // HF_CPR_CHFPZ2
    int chop_P2 = 0; // HF_CPR_CHFPP2
    double calibcurrent = 0.0; // HF_CPR_Cal_Heater_C
    double bias_H = 0.0; // HF_CH1_MXBIAS_V
    double magnetcurrent_H = 0.0; // HF_CH1_MX_MG_C
    double bias_V = 0.0; // HF_CV1_MXBIAS_V
    double magnetcurrent_V = 0.0; // HF_CV1_MX_MG_C
    double chopper = -4.0 in [-8.88,8.5]; // HF_CPR_Chopper_Rot
    double diplex_H = 0.0; // HF_CH1_DPACT_C
    double diplex_V = 0.0; // HF_CV1_DPACT_C
}{
    //check prime or redundant keyword
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_or_redundant"],"0",0.0);
    if(result_d[0]{1} == "prime") {
        Hifi_HIFI_P_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    } else {
        Hifi_HIFI_R_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    }
    //
}

// HIFI goto SAFE, procedure
//
procedure HIFI_goto_SAFE_fm {
}{
    Hifi_HIFI_goto_safe();
    {double,string}[] result = ConfigurationReader("name_delays",["stdby_delay","wbs_config_delay","hrs_config_delay","config_fpu_delay"],"0",0.0);
    delay(iround(result[0]{0} + result[1]{0} + result[2]{0} + result[3]{0}));
}

/////////////////////////////////////////////////////////////////
// Slow chop dual beam switch observing mode
// 
// Implemented as procedure returning time and noise levels for HSPOT
{string,double,double}[] procedure HifiPointProcDBSSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // Get the drift parameters to compute the drift noise
    {double,double} phaselengths = DBSPhaseLengths(band,lo_freq,effResolution,continuumDetection,oneGHzReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_switch_on_guess = imax(iceil(phaselengths{0} / (2.0 * double(data_time_guess))),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,2 * n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)}];

    return retvalues;
}

//HIFI-COP-2.1-CPR-RespTime
obs HifiEng_Chopper_Response_time_COP {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Chopper_Response_time_COP_proc_ops(prime_or_redundant));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Chopper_Response_time_COP_proc_ops(prime_or_redundant);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

////////////////////////////////////
// DBS raster observing mode - special version for Jupiter
// 
// Return time and noise levels
{int,double,double,double,double,double} obs HifiMappingProcJupiterDBSRaster {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,100]; // Number of rows in the map
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the raster line
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Engineering - Jupiter - DBS Raster Map slowChop",{data_time,0,0,n_switch_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    // Two changes relative to the normal DBS raster
    // 1) The longer load duration is enforced by zero resolution
    {double,double} loadResolution = {0.0,effResolution{1}};
    // 2) I assume that the tuning duration does not depend on the tuning level
    // so that the normal pre_timing can be reused.
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = DBSRaster_pre_timing(nlines,npoints,band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    // Check for NoddingInRaster or NoddingOfRaster
    int scansize = pre_timing{10};
    if(scansize > 1) {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,double,double,int,int,int,int,int} tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        // Dummy call to spacecraft command
        int[] telescopetimes = nodding_of_raster_pointing(false,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double,int,int,int,double,double,int,int,int,int} tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        telescopetimes = nodding_raster_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSRaster_post_timing(pre_timing,telescopetimes,nlines,npoints,n_switch_on,n_cycles,load_interval,false);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    if(scansize > 1) {
        tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        // Call telescope command
        telescopetimes = nodding_of_raster_pointing(true,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        telescopetimes = nodding_raster_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        JupiterDBSRaster_commanding(band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,false);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = DBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints,n_cycles,n_seq * imax(n_load,1),tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// FPU settling time for a mixer band change, 1st block
// Block for first tuning
block FPU_Settling_time_first_tuning_fm HIFI 3683 {
    string band_1 = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int int_time1 = 3600; //Integration time after first tuning
    double lo_freq_1 = 500.0; //LO frequency in sub-band a
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //
    //Tune of LO. We must use: configuration from safe to tuned.
    LCU_config_nominal_proc_fm(band_1,lo_freq_1);
    LO_tuning_w_mixerchoice_proc(band_1,lo_freq_1,"H");
    //
    //Configure spectroscopy integration
    Configure_Spectrometer_proc_fm(band_1,int_time1,["wb1","wb1"],backend);
    //4 sec. integration
    //Take series of spectra during int_time1 seconds
    HIFI_Spectr_total_power_proc_fm(band_1,backend,int_time1);
    //
    //Now switch off LO sub-band
    LCU_switch_off_proc_fm();
}

// Continuous HIFI integration with given backend settings at source
block HIFIContOnIntegration HIFI 6022 {
    int n_int = 1; // Integration time counter
    int data_time = 4; // Integration time between two data readouts
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_tp_proc_aot(n_int,data_time,rates);
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of DBS-raster observing mode
{int,int,int,int,int,int,int,int,int,int,int,int,int} procedure FastDBSRaster_pre_timing {
    int nlines_tot = 1 in [1,100]; // Number of rows in the map
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 10 in [4,80]; // data dump interval
    int n_int = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_data = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Fixed timings in the fast-chop mode
    int readouttime = data_time;
    int load_datatime = GetStdLoadReadout(band,lo_freq);
    // It should be investigated wehther we can use fast-chop on loads as well
    // Perform consistency checks
    int single_data = data_time / 2;
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,single_data);
    // Check chopper frequency
    CheckFastChopFrequency(band,lo_freq,data_time,n_int,n_data);
    // Is the map size an integer multiple of the scan size?
    CheckReasonableLineNumber(nlines_tot * npoints,false);
    int scansize = n_pointsperscan;
    if(scansize > nlines_tot * npoints) {
        SError("Scan size exceeds the total map size.");
    }
    if(nlines_tot * npoints % scansize != 0) {
        SError("Map size is no integer multiple of the scan size.");
    }
    int n_scans = nlines_tot * npoints / scansize;
    // Compute parameters for the instrument timing
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    int inttime = readouttime * n_data;
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms));
    int readoutdead = FastChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,true);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,false);
    }
    initlength = initlength + loadlength;
    // compute the load interval in case of short scan_time
    int scan_time = inttime * scansize;
    int n_loadinterval = imax(load_interval / scan_time,1);
    // Special treatment for nodding_raster due to limitations in API
    // Split into loads per point or per multiple points
    if(scansize == 1 && n_loadinterval > n_cycles) {
        n_loadinterval = n_cycles * (n_loadinterval / n_cycles);
    }
    n_loadinterval = imin(n_loadinterval,n_cycles * n_scans);
    // Compare load interval and nodding interval
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    if(load_spacing < readouttime) {
        SError("Load period shorter than backend readout period.");
    }
    // load measurements within a single point integration
    int n_load = inttime / load_spacing;
    if(n_load >= 1 && scansize > 1) {
        SError("Number of points in one scan too large for load period.");
    }
    // Rough estimate of the pointing time - this is corrected
    // after the evaluation of the telescope command
    if(load_spacing > 2 * scan_time) {
        int n_seq = n_data;
        int pointing = inttime + jitterdead;
    } else {
        // It is possible that a single point is short enough, but a scan
        // too long. Then everything is reduced to a single point.
        scansize = 1;
        n_scans = nlines_tot * npoints;
        n_seq = n_data / (n_load + 1);
        inttime = n_seq * (n_load + 1) * readouttime;
        pointing = inttime + (n_load + 1) * loadlength + jitterdead;
    }
    // dangling time given by readout dead time
    int dangling = readoutdead;
    int holdlength = jitterdead;
    // Return all the times needed for telescope call and post_timing processing

    return {inttime,pointing,readouttime,loadlength,holdlength,load_spacing,n_load,n_loadinterval,n_seq,n_scans,scansize,initlength,dangling};
}

//Imix characterisation for HEB
block HEB_Imix_calibration_block_fm HIFI 3918 {
    string band = "6a" in ["6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 1520.0; //LO frequency  
}{
    string tab = "config_HEB_Imix.config";
    double bandnb = GetBandCode(band);
    double lofreq_imixcal = dlookup(tab,"" + iround(bandnb),"frequency");
    double idip1 = dlookup(tab,"" + iround(bandnb),"idip1");
    double beta = dlookup(tab,"" + iround(bandnb),"beta");
    double length_dip = dlookup(tab,"" + iround(bandnb),"length");
    int step = ilookup(tab,"" + iround(bandnb),"step");
    //
    //Compute Idip2 according to model
    double idip2 = min(1.1 * (150.0 / lo_freq) * (180.0 / (3.1415 * beta * length_dip)),2.24);
    //
    {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
    int ivc_step = 40;
    //Allows one single pass
    //Loop on diplexer currents
    double idip = idip1;
    for(int i = 1 .. step) {
        Set_Diplexer_current_proc_fm(idip,idip);
        //IVC between 3.5 and 0.5mV
        double ivc_start = 3.5;
        double ivc_end = 0.5;
        double step_duration = 0.1;
        double stepsize = Stepsize(min(ivc_start,ivc_end),max(ivc_start,ivc_end),ivc_step - 1,"hifi_HIF_mxbias_step_V");
        double margin = Stepmargin(min(ivc_start,ivc_end),max(ivc_start,ivc_end),"hifi_HIF_mxbias_step_V");
        Hifi_HIFI_FCU_parameter_scan($BBID,ivc_step,1,step_duration,ivc_start,ivc_start,-1.0 * (stepsize + margin),0.0,0.0,0.0);
        int duration_ivcurve = iceil(double(ivc_step) * step_duration);
        delay(duration_ivcurve + 2);
        //Increase idip
        idip = double(i) * (idip2 - idip1) / double(step - 1);
    }
}

//Slow chop between sky and HBB, block
block Sky_Hot_fm_COP HIFI 3929 {
    string band = "1a";
    int integ_time = 4; //Total integration time for delay computation
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,etc
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast 
}{
    //Fetch respective chopper angles
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_M3","chop_hot"],band,0.0);
    double chop_M3 = result[0]{0};
    double chop_hot = result[1]{0};
    //
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"slowchop",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    HIFI_Spectr_slow_chop_proc_fm(chop_hot,chop_M3);
    Apply_Slow_Chop_delay(integ_time,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// Integrate with IF1 off, block
// We take 1 spectrum per phase.
block Stability_IF_system_fm HIFI 3422 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integrations
    int integ_time = 4; //Total integration time in sec. to be set at end of test 
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
}{
    Start_block();
    //The system as is should be ready
    //No use of FPU capabilities.
    //
    //Do a long integration: 4 sec. is OK
    //We implement a special spectroscopy configuration with fixed values
    Total_power_spectro_for_Stability_proc_fm(band,n,integ_time,backend,hrs_mode);
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure SingleChopNoRef_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int n_chop_on = 1; // number of half load-sky-sky-load cycles on ON
    bool fs = false; // whether frequency switch used
    double tscan = 10.0; // Total average duration of one scan
    double tdead = 0.05; // Average dead time in one chop cycle
}{
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    double idealnoise = idealvalues{1} * idealvalues{1};
    double obsnoise = noisevalues{0} * noisevalues{0};
    double efficiency = idealnoise / obsnoise;
    // Compute the actual integration time
    double inttime = (tscan - tdead) / 2.0;
    double posinttime = double(n_chop_on) * 2.0 * inttime;
    double posofftime = 0.0;
    // Check total integration time
    double timeefficiency = (posinttime + posofftime) / double(totaltime);
    // Noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posofftime,timeefficiency,efficiency,relnoise,fs);
}

//////////////////////////////////////////////////////////////////////
// Determine data readout period and corresponding data rate
// External wrapper to determine automatically the WBS bit size
{int,double[]} procedure DataTaking {
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // Readout parameters for HRS1,HRS2, WBS1,WBS2
    int data_time = 4; // Integration time between two data readouts
}{
    // 16 bit format for short integrations
    int wbs16bitlimit = 5;
    if(data_time <= wbs16bitlimit) {
        bool mode16bit = true;
    } else {
        mode16bit = false;
    }
    {int,double[]} dataparms = AllDataRates(backendreadoutparms,data_time,mode16bit);

    return dataparms;
}

/////////////////////////////////////////
// Testmodes for handling of LCU safety
// tables and memory patches
// AdJ - 17-08-2006
// Reviewed on 13-10-2006 to solve SPR 0866
// Reviewed on 06-11-2006 to include memory patching
// Reviewed on 20-06-2007 flight procedure limit of 999 command parameters
/////////////////////////////////////////
//modes: see fm_testmodes.cus
//////////////////////////////////////
// blocks
//////////////////////////////////////
//Upload of LCU safety table, block
block LcuSafetyTableUpload_fm HIFI 3900 {
    int start = 0; // first table entry to upload (count from zero)
    int count = 0; // maximum number of table lines to upload
}{
    //Start_block();
    string section = GetLcuSection();
    string tab = "LcuSafetyTable_" + section + ".config";
    int total = imin(table_size(tab),start + count);
    int done = start;
    if(total > 0) {
        int[] allIndices = icolumn(tab,"tableindex");
        int[] allValues = icolumn(tab,"value");
        int[] index = [];
        int[] value = [];
        int next = 0;
        while(done < total) {
            for(int i = 0 .. 24) {
                next = imin(done,total - 1);
                index[i] = allIndices[next];
                value[i] = allValues[next];
                done = done + 1;
            }
            Hifi_HIFI_Configure_LCU_table($BBID,index[0],value[0],index[1],value[1],index[2],value[2],index[3],value[3],index[4],value[4],index[5],value[5],index[6],value[6],index[7],value[7],index[8],value[8],index[9],value[9],index[10],value[10],index[11],value[11],index[12],value[12],index[13],value[13],index[14],value[14],index[15],value[15],index[16],value[16],index[17],value[17],index[18],value[18],index[19],value[19],index[20],value[20],index[21],value[21],index[22],value[22],index[23],value[23],index[24],value[24]);
            delay(1);
        }
    }
}

//Set DC bias without switching on the chain, block
//All input parameters shall be given by the user
block Conf_diag_LCU_block_fm HIFI 3662 {
    string band = "1a" in ["ALL","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double plevel_v = 0.0; // HL_PL_C
    double m1_v = 0.0; // HL_M1_V
    double m2_v = 0.0; // HL_M2_V
    double m3_v = 0.0; // HL_M3_V
    double gate1_v = 0.0; // HL_Gate1_V
    double gate2_v = 0.0; // HL_Gate2_V
    double drain1_v = 0.0; // HL_Drain1_V
    string curlim1_v = "1.5" in ["1.5","1.3","1.22","1.4"]; // HL_Curlim1
    double drain2_v = 0.0; // HL_Drain2_1A_V
    string curlim2_v = "1.5" in ["1.5","1.3","1.22","1.4"]; // HL_Curlim2  
}{
    //
    //Start_block();
    //
    //Execute configuration
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_diag_LCU_ch1a($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_diag_LCU_ch1b($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_diag_LCU_ch2a($BBID,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_diag_LCU_ch2b($BBID,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_diag_LCU_ch3a($BBID,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_diag_LCU_ch3b($BBID,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_diag_LCU_ch4a($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_diag_LCU_ch4b($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_diag_LCU_ch5a($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_diag_LCU_ch5b($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_diag_LCU_ch6a($BBID,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_diag_LCU_ch6b($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_diag_LCU_ch7a($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_diag_LCU_ch7b($BBID,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v);
    }
    //
    {double,string}[] result = ConfigurationReader("name_delays",["config_lo_delay"],"0",0.0);
    int config_lo_delay = iround(result[0]{0});
    delay(config_lo_delay);
    //
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double} procedure SScanDBS_deadtimes {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int grouplen = 1; // Number of frequency steps per nodding phase
    int data_time = 4; // chunk size
    int n_bchop = 1; // Normal number of chop cycles per frequency and pointing
    int n_long = 1; // Chop cycles per frequency and pointing without retuning
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    double avnumchop = 1.0; // Average number of chop cycles per frequency
    double tdead = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Compute parameters for the instrument timing in normal phases
    {double,double} tinst = GetInstDeadSlowChop(data_time,2 * n_long,"chop",band,lo_freq,backendreadoutparms);
    // dead time
    double tdeadint = double(data_time * 2 * n_long) - tinst{0};
    // subtract dead times in switches
    // keep dead times between A-A and B-B in total dead time
    tdeadint = tdeadint - double(n_long) * tinst{1};
    // treat integration times of other frequencies as dead time
    double tdeadother = double(data_time * 4 * n_long);
    // Store
    double tswitch = tinst{1};
    // Integration time
    double tphaseint = tinst{0};
    // Correcton in case of cycles with shorter integrations
    if(n_cycles > 1) {
        tinst = GetInstDeadSlowChop(data_time,2 * n_bchop,"chop",band,lo_freq,backendreadoutparms);
        // dead time
        double tdeadshort = double(data_time * 2 * n_bchop) - tinst{0};
        // subtract dead times in switches
        tdeadshort = tdeadshort - double(n_bchop) * tinst{1};
        // weigh
        tdeadint = (tdeadint * double(n_cycles - 1) + tdeadshort) / double(n_cycles);
        tphaseint = (tphaseint * double(n_cycles - 1) + tinst{0}) / (2.0 * avnumchop * double(n_cycles));
        tdeadother = (tdeadother * double(n_cycles - 1) + double(data_time * 4 * n_bchop)) / double(n_cycles);
    } else {
        tphaseint = tphaseint / (2.0 * avnumchop);
    }
    // Total dead time per cycle
    double tdead_tot = tdead + 2.0 * tdeadint;
    // Add integration times of other frequencies as dead time
    tdead_tot = tdead_tot + double(grouplen - 1) * tdeadother;

    return {tdead_tot,tphaseint,tswitch};
}

//HIFI LO tuning, block
//Target current in entered as input parameter
block LO_tuning_w_targetC_block_fm HIFI 3628 {
    double target_current = 1.0; //Target mixer current
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string mixer_polarization = "H" in ["H","V"]; //The polarization to be used for the tuning
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    //mixer_polarization = result[0]{1};
    //Get target mixer current: from input
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //For all bands, scan will be done with decreasing drain2 voltages
    //The best guess is taken from look-up table
    double tune_range = 0.1;
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double middle_d2 = result[0]{0};
    double drain2_v_start = min(middle_d2 * (1.0 + tune_range / 2.0),drain2_bluemax);
    double drain2_v_end = (1.0 - tune_range / 2.0) / (1.0 + tune_range / 2.0) * drain2_v_start;
    step_drain2_v = (drain2_v_end - drain2_v_start) / double(nsteps - 1);
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum,config_lo_delay);
    //
    //delay(5);	//to settle at this value
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    delay(1);
    //
    //Execute tuning: check which mixer is to be used
    if(mixer_polarization == "V") {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCV($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCV($BBID,target_current);
        }
    } else {
        if(band == "5a" || band == "5b") {
            Hifi_HIFI_Tune_LO5_Using_MXCH($BBID,target_current);
        } else {
            Hifi_HIFI_Tune_LO_Using_MXCH($BBID,target_current);
        }
    }
    //
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //
    //Store settings into available register
    HIFI_HL_store_tm_only_proc_fm();
    //
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

// Global slow chop spectroscopy for stability measurement, procedure
procedure Slow_chop_spectro_for_Stability_proc_fm {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integrations
    int integ_time = 8; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    double chop1 = 3.4; //First chopper position
    double chop2 = 4.7; //Second chopper position
}{
    //First derive backend setting codes as expected by VO's routine
    //Build up backend parameter tupple:
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    // Readout parameters for HRS1,HRS2, WBS1,WBS2
    //Compute data_time and n_switch using the wrapper
    int[] res = ConfigSlowChop(integ_time,"chop",band,0.0,backendreadoutparms);
    int data_time = res[0];
    int n_switch = n * res[1];
    //For stability measurement, the number of loop is a user input
    // Now call the spectroscopy setup: it is common to ILT and AOT CUS.
    // The deadtimes output is not used at ILT level.
    {double,double} dtimes = ConfigSpectroscopySlowChop(data_time,n_switch,"chop",band,0.0,backendreadoutparms,true);
    //Compute data-rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //Now start the long integration
    HIFI_Spectr_slow_chop_proc_fm(chop1,chop2);
    //Apply delays
    Apply_Slow_Chop_delay(data_time * n_switch,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// Set diplexer currents for both polarizations, block
block Set_Single_Diplexer_current_block_fm HIFI 3744 {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 522.0; //The LO frequency in GHz 
    string polarization = "H" in ["H","V"]; //The polarization on which the test is done
}{
    //Start_block();
    if(band == "3a" || band == "3b" || band == "4a" || band == "4b" || band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        if(polarization == "H") {
            Hifi_HIFI_CH1_DPACT_C($BBID,result_dip[0]);
        } else {
            Hifi_HIFI_CV1_DPACT_C($BBID,result_dip[1]);
        }
    }
    delay(1);
}

// Needs the chopper in open-loop mode !!
block Chopper_closed_loop_parameter_check_block_ops HIFI 7695 {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //StartBlock_ops();
    //Move chopper to 0V
    mois_step("Move chopper to 0V");
    double targetAngle = 0.0;
    if(prime_or_redundant == "Prime") {
        Hifi_HIFI_P_Chopper_Rot($BBID,targetAngle);
    } else {
        Hifi_HIFI_R_Chopper_Rot($BBID,targetAngle);
    }
    //Hifi_HIFI_non_periodic_hk_FCU ();		//To get sent voltage
    delay(1);
    mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to 0V");
    //Go to -7.09V and monitor short term stabilisation
    int milliSecSample = 3;
    // interval between samples
    int samplesBefore = 50;
    int samplesAfter = 1000;
    targetAngle = -7.09;
    mois_step("Monitor chopper LVDT when moving from 0V to -7.09V");
    Engineering_scan_for_closed_loop_scan_ops(targetAngle,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    //mois_tmcheck("Check arrival of TBD TM packet");
    mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to -7.09V");
    //
    //Monitor chopper position while staying at -7.09V
    milliSecSample = 10;
    // interval between samples
    //This special procedure does not change prime angles into red angles
    mois_step("Monitor chopper LVDT when stable at -7.09V");
    Engineering_scan_for_closed_loop_scan_ops(targetAngle,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    //
    //Move chopper to 0V
    mois_step("Move chopper back to 0V");
    targetAngle = 0.0;
    if(prime_or_redundant == "Prime") {
        Hifi_HIFI_P_Chopper_Rot($BBID,targetAngle);
    } else {
        Hifi_HIFI_R_Chopper_Rot($BBID,targetAngle);
    }
    //Hifi_HIFI_non_periodic_hk_FCU ();		//To get sent voltage
    delay(1);
    mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to 0V");
    //
    //Move to -0.37 and monitor short term stabilisation
    milliSecSample = 3;
    // interval between samples
    targetAngle = -0.37;
    //This special procedure does not change prime angles into red angles
    mois_step("Monitor chopper LVDT when moving from 0V to -0.37V");
    Engineering_scan_for_closed_loop_scan_ops(targetAngle,milliSecSample,samplesBefore,samplesAfter,prime_or_redundant);
    mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to -0.37V");
    //
    //Move back to rest position: this one depends on prime/red
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    mois_step("Move chopper back to rest position");
    if(prime_or_redundant == "Prime") {
        Hifi_HIFI_P_Chopper_Rot($BBID,result[0]{0});
    } else {
        Hifi_HIFI_R_Chopper_Rot($BBID,result[0]{0});
    }
    //Hifi_HIFI_non_periodic_hk_FCU ();		//To get sent voltage
    delay(1);
    mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to " + result[0]{0});
    //  
}

//HRS Functional Test #0, procedure: right after switch on, BEFORE HK collection
procedure HRS_functional_test_No_0_proc_ops {
}{
    mois_comment("Performing HRS Functional Test #0");
    //Use new command implemented in SCR-859
    Hifi_HIFI_HRS_functional_test($BBID,0,"BOTH");
    delay(5);
    //
}

//General LO configuration command
block HIFI_Configure_LCU_block_aot HIFI 6617 {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; //LO frequency
    int freq_nx = 0; // HL_freq_nx
    int lsu_main = 0; // HL_LSU_main
    int lsu_offset = 0; // HL_LSU_offset
    int d2_step = 1; // HL_D2_step
    double plevel_v = 0.0;
    double m1_v = 9.0;
    double m2_v = -2.0;
    double m3_v = 0.0;
    double gate1_v = -2.5;
    double gate2_v = -2.5;
    double drain1_v = 2.8;
    string curlim1_v = "1.4";
    double drain2_v = 2.6;
    string curlim2_v = "1.4";
    int macro_checksum = 0; // HL_macro_checksum
    int config_lo_delay = 6;
}{
    //Check that Vd2 is within the blue limits
    drain2_v = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v);
    //
    //
    //Execute configuration
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_safe_LCU_ch1a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_safe_LCU_ch1b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_safe_LCU_ch2a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_safe_LCU_ch2b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_safe_LCU_ch3a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_safe_LCU_ch4a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_safe_LCU_ch4b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
    delay(config_lo_delay);
    //
    //Read TM pages and clear error flags
    LCU_Read_TM_pages_proc_aot();
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure JupiterFastDBS_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 10 in [4,80]; // data dump interval
    int n_int = 20; // number chop cycles to integrate in ICU before transfer
    int n_seq = 1; // Number of continuous data transfer cycles
    int n_load = 0; // additional load measurements in one pointing phase
    int n_loadinterval = 10; // number of nods before a load measurement
    bool end_load = false; // Need for load after each pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    int shiftlength = 10; // Shift of the loop start relative to the pointing
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Fixed timings in the fast-chop mode
    int load_datatime = GetStdLoadReadout(band,lo_freq);
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time / 2);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,true);
    int readoutdead = FastChopReadoutDelay(band,lo_freq,backendreadoutparms);
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    int[] choppars = [2 * n_int,0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"jupiter");
            }
            delay(tinitslew - (time() - startobs) - loadlength + shiftlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            if(shiftlength > 0) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i1 = 1 .. n_load) {
                HIFIFastChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFIFastChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            // Second phase in first nod position
            // occurs for even cycle numbers
            runintostate = false;
            if(state[2] % 2 == 0) {
                if(end_load) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // A nod slew follows - active HK if not used by load measurement
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 7) {
            // second nod position
            choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            for(int i2 = 1 .. n_load) {
                HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            // First phase in second nod position
            // occurs for odd cycle numbers
            runintostate = false;
            if(state[2] % 2 == 1) {
                if(end_load) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // A nod slew follows - active HK if not used by load measurement
                if(state[2] % n_loadinterval > 0) {
                    HIFIActiveHK("normal",tnodslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            runintostate = false;
        }
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                // ( Does not occur if end_load is set)
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

//Get maximum value for vector_scan_BLUE_LIMIT
double procedure Get_BLUE_LIMIT_D2_proc_fm {
    string band = "4a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band   
    double lo_freq = 978.2; //LO Frequency
}{
    //Implementation of SCR-2220
    string name_configlcu = "name_configlcu_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlcu = "name_configlcu_b";
    }
    {double,string}[] result = ConfigurationReader(name_configlcu,["drain2_v_blmn","drain2_v_blmx"],band,lo_freq);
    //Fetch offset to apply to blue max
    double[] cresult = CalibrationReader("name_blueoffset",["blueoffset"],band,0.0);
    double bloff = cresult[0];
    //
    double drain2_max = 0.0;
    if(band == "1a") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "1b") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "2a") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "2b") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "3a") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "3b") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "4a") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "4b") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "5a") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "5b") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "6a") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "6b") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "7a") {
        drain2_max = result[1]{0} - bloff;
    }
    if(band == "7b") {
        drain2_max = result[1]{0} - bloff;
    }

    return drain2_max;
}

//////////////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing of OTF observing mode
{int,int,int,int,bool,int,int} procedure OTFFSwitchNoRef_pre_timing {
    int nlines = 1; // Number of rows in the map
    int npoints = 10; // Number of data dumps per row
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int n_chop_on = 2 in [1,3600]; // number of half nu1-nu2-nu2-nu1 cycles per point
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq + min(freq_throw,0.0),lo_freq + max(freq_throw,0.0));
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    CheckFswOutOfBand(band,lo_freq,freq_throw,backendreadoutparms);
    // jitter treatment is already taken into account by ValidMapSize
    // Compute parameters for the instrument timing
    int lineint = npoints * n_chop_on * 2 * data_time;
    int nlines_tot = nlines * n_cycles;
    // compute load integration time
    int loadlength = duration(DoubleLoadMeasurement(band,lo_freq,freq_throw,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Compute the scan size from the load interval
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,npoints * 8);
    // Here, we do not know the turn around-time yet. Ignored until post_timing
    int n_loadinterval = load_spacing / lineint;
    if(n_loadinterval < 1) {
        SError("Scan duration too long for load period. " + "Reduce the number of chop cycles.");
    }
    // Make sure that load slews occur at the same position in each coverage
    CheckReasonableLineNumber(nlines,true);
    n_loadinterval = IMultiple(n_loadinterval,nlines);
    // If no load required parameter has to be 0
    if(n_loadinterval > nlines_tot) {
        // Determine need for final load measurement
        double rest = double(nlines_tot % n_loadinterval) + 0.5;
        bool end_load_on = rest > 0.5001 * double(n_loadinterval);
    } else {
        if(n_loadinterval > nlines) {
            n_loadinterval = nlines;
        }
        // In all these cases a final load will be made anyway in regular pattern
        end_load_on = false;
    }
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFIFsw(band,lo_freq,freq_throw,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,true);
    }
    initlength = initlength + loadlength;
    // Dangling load measurement not counted here, only dangling readout
    int dangling = readoutdead;
    // Return all the times needed in the observing mode modules
    // The holdlength parameter is abused for lineint here

    return {loadlength,load_spacing,n_loadinterval,lineint,end_load_on,initlength,dangling};
}

//Readback of LCU safety table, block
block LcuSafetyTableReadback_fm HIFI 3901 {
}{
    Start_block();
    for(int band = 1 .. 7) {
        for(int fIndex = 0 .. 31) {
            Hifi_HIFI_non_periodic_hk_LCU(fIndex,"channel_" + band + "a");
            delay(2);
            Hifi_HIFI_non_periodic_hk_LCU(fIndex,"channel_" + band + "b");
            delay(2);
        }
    }
}

//HIFI LO tuning only for M1 investigation in 7b, block
//Target current is read from look-up table
block LCU_config_w_M1_block_fm HIFI 3916 {
    string band = "7b"; // HIFI band
    double lo_freq = 1890.0; //LO frequency
    double m1 = -5.0; //M1 multiplier voltage
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    string mixer_polarization = result[0]{1};
    //
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = m1;
    //result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    //multiplier settings which are not passed as input must be
    //taken from safe table
    if(band == "3b") {
        double[] cresult = CalibrationReader("name_lcu_safe_values",["m1_v","m2_v","m3_v"],band,lo_freq);
        m2_v = cresult[1];
        m3_v = cresult[2];
    }
    //
    cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //Adjust scan
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    //
    //Maximum Vd2 will be set
    double drain2_v_start = drain2_bluemax;
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    //Send command
    if(band == "3b") {
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum);
        //Send command: specific to M3 in 3b
        delay(config_lo_delay);
        //
        //Additional read of TM pages
        LCU_Read_TM_pages_proc_fm();
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,macro_checksum);
        //
        delay(config_lo_delay);
        //
        //Additional read of TM pages
        LCU_Read_TM_pages_proc_fm();
    }
    //
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure OTF_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int nlines = 20; // Number of lines in the map
    int npoints = 20; // Number of points in the map
    int n_scans = 2; // Number of OTF scans to cover the map
    int n_cycles = 1; // Number of map coverages
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double} tact = {10.0,4.0,12.0}; // field of actual timings
}{
    double tint_act = tact{1};
    // integration time excluding all dead times
    double tintoff = tact{2};
    // integration time on OFF
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    double idealnoise = idealvalues{1} * idealvalues{1};
    double obsnoise = noisevalues{0} * noisevalues{0};
    // rescale for map coverage
    idealnoise = idealnoise * double(npoints * nlines);
    double efficiency = idealnoise / obsnoise;
    // Compute the actual integration time
    double posinttime = double(n_cycles * nlines * npoints) * tint_act;
    double posofftime = double(n_cycles * n_scans + 1) * tintoff;
    int instrumenttime = iceil(double(n_cycles * n_scans) * tscan + tintoff);
    // Check total integration time
    double timeefficiency = (posinttime + posofftime) / double(totaltime);
    // Noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // Non-standard messages
    message("</p><p>");
    message("The observed map consists of " + nlines + " OTF lines, each covering " + npoints + " readout points.<br>");
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posofftime,timeefficiency,efficiency,relnoise,false);
}

// Standing wave analysis, mode NDW
//HIFI-COP-3-StWv1
procedure Standing_wave_noretune_COP_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    int freq_index = 1; //The frequency index to consider: 1 to 4
    string los_code = "sc" in ["sc","sh","ss"]; //The line-of-sight code: sc (sky-CBB), sh (sky-HBB), ss (sky-sky)
}{
    //Retrieve frequencies from LUT
    string tabstwv = "config_stwvfreq.config";
    double bandnb = GetBandCode(band);
    //
    //Check consistency of request
    if(freq_index > 1 && (los_code == "sh" || los_code == "ss")) {
        error("You cannot select this line-of-sight with this frequency index");
    }
    if(iround(bandnb) % 2 == 0 && (los_code == "sh" || los_code == "ss")) {
        error("You cannot select this line-of-sight with b-bands");
    }
    //Fetch observing parameters
    double lo_freq = dlookup(tabstwv,"" + iceil(bandnb),"freq" + freq_index);
    int integ_time = ilookup(tabstwv,"" + iceil(bandnb),"t" + freq_index);
    int total_stepnb = ilookup(tabstwv,"" + iceil(bandnb),"n" + freq_index + "_" + los_code);
    //
    if(lo_freq == 0.0) {
        error("There is no frequency associated with this band and this frequency index");
    }
    //
    HRS_config_block_fm(band,hrs_mode);
    //
    int[] res = [0,0];
    if(los_code == "sh") {
        res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    } else {
        res = Configure_Spectrometer_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    }
    int total_time = res[0] * res[1];
    //
    double step = 0.015;
    //GHz
    double stepnb = double(total_stepnb / 2);
    double[] lo_freq_input = [0.0,0.0,0.0];
    //Build lo_freq_input array
    lo_freq_input = [lo_freq - stepnb * step,lo_freq + stepnb * step,step];
    Standing_wave_noretune_fm_COP(band,total_time,hrs_mode,backend,lo_freq_input,los_code);
    //
}

// Diplexer scan, fast, procedure
// Measures mixer current (thru HK thus), also suitable to just set the diplexer
procedure Diplexer_scan_fast_proc {
    string band = "3a"; // HIFI band		//Setting file
    double diplexer_current_min_h = -2.24; //minimum diplexer current H
    double diplexer_current_max_h = 2.24; //maximum diplexer current H
    double diplexer_current_min_v = -2.24; //minimum diplexer current V
    double diplexer_current_max_v = 2.24; //maximum diplexer current V
    int n_steps = 100; //number of steps
    double lo_freq = 807.0; //LO frequency
    string mixer_polarization = "H" in ["H","V"]; //Polarization: H or V
}{
    //
    //In case of band 6 or 7, use special biases
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v","bias_max_h","bias_max_v"],band,lo_freq);
        //First go to 4mV
        Mixerbias_block_fm(result[2]{0},result[3]{0});
        //Then to 3mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //
    //Fetch diplexer settings
    double[] result_dip = Get_Diplexer_setting(band,lo_freq);
    double diplex_H = result_dip[0];
    double diplex_V = result_dip[1];
    //Case of H polarization
    if(mixer_polarization == "H") {
        //diplexer_current_min_v = diplex_V;
        diplexer_current_max_v = diplexer_current_min_v;
        Diplexer_scan_fast_fm(band,diplexer_current_min_h,diplexer_current_max_h,diplexer_current_min_v,diplexer_current_max_v,n_steps);
    }
    //Case of V polarization
    if(mixer_polarization == "V") {
        //diplexer_current_min_h = diplex_H;
        diplexer_current_max_h = diplexer_current_min_h;
        Diplexer_scan_fast_fm(band,diplexer_current_min_h,diplexer_current_max_h,diplexer_current_min_v,diplexer_current_max_v,n_steps);
    }
    //Get back to optimal settings
    Set_Diplexer_current_block_fm(diplex_H,diplex_V);
    //
    //In case of band 6 or 7,go back to nominal values
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        //First go to 4mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
        //Then to nominal
        result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //
}

// Total power integration for peak up
block HIFIPeakupIntegration HIFI 6821 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // number of readouts
    bool isWbs = true; // backend to use - resolution
    bool isH = true; // backend to use - polarization
    int point = 1; // Number of point in 3x3 raster
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    // First part - actual peakup data aquisition
    // polarization string
    if(isH) {
        string polarization = "H";
    } else {
        polarization = "V";
    }
    // Call command
    if(isWbs) {
        Hifi_HIFI_acquire_peakup_wbs($BBID,polarization,point);
    } else {
        Hifi_HIFI_acquire_peakup_hrs($BBID,polarization,point);
    }
    delay(2);
    // Second part additional data frame aquisition
    HIFI_Spectr_slow_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_M3","chop_M3right"],rates);
    // Move chopper back to center position
    RotateChopper(band,lo_freq,"chop_M3");
}

////////////////////////////////////
// Frequency switch observing mode
// 
// All properties inherited from the load-chop mode
//
// This whole implementation is highly speculative as we have no experience
// with frequency switch measurements yet.
//
{int,double,double,double,double,double} obs HifiPointProcFSwitch {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    bool refSelected = true; // Dummy parameter required by HSPOT
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int n_switch_off = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF calibration cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Single Point - Frequency Switch Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,0,0,0,n_cycles,load_interval});
    // position switch
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} pre_timing_ps = FSwitch_pre_timing(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_cycles,load_interval,docommands);
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar_ps = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,pre_timing_ps,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar_ps{0},tpar_ps{1},tpar_ps{2},tpar_ps{3},tpar_ps{4},tpar_ps{5},tpar_ps{6},tpar_ps{7},tpar_ps{8},tpar_ps{9},tpar_ps{10},tpar_ps{11},tpar_ps{12},tpar_ps{13},tpar_ps{14},tpar_ps{15},tpar_ps{16},tpar_ps{17},tpar_ps{18},true);
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},int,bool,double,double} post_timing_ps = DoubleChop_post_timing(pre_timing_ps,telescopetimes,n_cycles);
    // Now the actual observation starts
    // Prepare telescope command
    tpar_ps = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,post_timing_ps{1},n_cycles);
    // Call telescope command 
    telescopetimes = nodding_pointing(true,tpar_ps{0},tpar_ps{1},tpar_ps{2},tpar_ps{3},tpar_ps{4},tpar_ps{5},tpar_ps{6},tpar_ps{7},tpar_ps{8},tpar_ps{9},tpar_ps{10},tpar_ps{11},tpar_ps{12},tpar_ps{13},tpar_ps{14},tpar_ps{15},tpar_ps{16},tpar_ps{17},tpar_ps{18},true);
    // Consistency check
    int totaltime = post_timing_ps{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    //////////////////////////////////////////////////////////////////////
    int on_inttime = post_timing_ps{1}{0};
    int off_inttime = post_timing_ps{1}{1};
    int on_pointing = post_timing_ps{1}{2};
    int off_pointing = post_timing_ps{1}{3};
    int loadlength = post_timing_ps{1}{4};
    int n_loadinterval = post_timing_ps{1}{7};
    int n_per_on = post_timing_ps{1}{8};
    int n_per_off = post_timing_ps{1}{9};
    int n_load_on = post_timing_ps{1}{10};
    int n_load_off = post_timing_ps{1}{11};
    bool end_load_on = post_timing_ps{1}{12};
    bool end_load_off = post_timing_ps{1}{13};
    int initshiftlength = post_timing_ps{2};
    bool final_load = post_timing_ps{3};
    double tscan = post_timing_ps{4};
    double tdead = post_timing_ps{5};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    //////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FSwitch_commanding(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_per_on,n_per_off,n_loadinterval,n_load_on,n_load_off,end_load_on,end_load_off,final_load,startobs,telescopetimes,loadlength,initshiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = DoubleChop_deadtimes("fs",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_per_on,n_per_off,n_load_on,n_load_off,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = FSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,on_inttime,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    DoubleChop_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,n_per_on * (n_load_on + 1),n_per_off * (n_load_off + 1),true,tscan,on_pointing,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//HIFI-COP-X-Dip-FSW
procedure Dip_FSW_COP_proc_ops {
    string band = "3a" in ["3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI band
    int throw_index = 1; //index of FSW throw as of stab FSW table of throws
    int freq_index = 1; //index of FSW throw as of stab FSW table of frequencies
    string[] hrs_mode = ["wb1","wb1"];
    int integ_time = 600;
    string backend = "both";
    int nb_pairs = 20; //number of FSW1-FSW2 pairs
    string polarization = "H" in ["H","V"]; //The polarization on which the test is done
    bool retune = true; //whether the diplexer is adjusted between frequencies or not
}{
    //
    //Define frequencies of interest: first freq. index of stab_freq_fsw
    string tab = "config_stabfreq_" + band + ".config";
    double lo_freq1 = dlookup(tab,"" + freq_index,"freq_fsw");
    //Get throw
    string tabfsw = "config_freqthrow.config";
    double bandnb = GetBandCode(band);
    double freq_throw = dlookup(tabfsw,"" + iceil(bandnb),"freq_throw_" + throw_index);
    double lo_freq2 = lo_freq1 + freq_throw / 1000.0;
    double lo_freq_ref = (lo_freq1 + lo_freq2) / 2.0;
    //Init MSA at FSW1 and on HBB for tuning
    //Tune FSW1 and store in register
    if(retune) {
        Init_MSA_HBB_fm(band,"CLOSE",lo_freq1,"ON");
        LO_tuning_FSW_block_fm(band,lo_freq1,lo_freq_ref,true);
    } else {
        Init_MSA_HBB_fm(band,"CLOSE",lo_freq_ref,"ON");
        LO_tuning_FSW_block_fm(band,lo_freq1,lo_freq_ref,true);
    }
    //Configure HRS
    HRS_config_block_fm(band,hrs_mode);
    //Magnet tuning: only bands 3 and 4
    if(band == "3a" || band == "3b" || band == "4a" || band == "4b") {
        Magnet_tuning_block_fm(band,lo_freq1,"HRS",40);
    }
    //Backend config and tuning
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        HRS_tune_block_fm(band);
    }
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        //WBS calibration
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    //
    //Tune FSW2 and store in register
    if(retune) {
        Set_Diplexer_current_FSW_block_fm(band,lo_freq2);
        LO_tuning_FSW_block_fm(band,lo_freq2,lo_freq_ref,false);
    } else {
        //Set_Diplexer_current_FSW_block_fm(band,lo_freq_ref);
        LO_tuning_FSW_block_fm(band,lo_freq2,lo_freq_ref,false);
    }
    //Perform hotcold at FSW1
    int[] res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    int total_time = res[0] * res[1];
    if(retune) {
        Set_Diplexer_current_FSW_block_fm(band,lo_freq1);
    } else {
        //Set_Diplexer_current_FSW_block_fm(band,lo_freq_ref);
    }
    Activate_FSW_register_block_fm("FSW1");
    Hot_cold(band,hrs_mode,backend,total_time,"slowchop",0,0);
    //Perform hotcold at FSW2
    if(retune) {
        Set_Diplexer_current_FSW_block_fm(band,lo_freq2);
    } else {
        //Set_Diplexer_current_FSW_block_fm(band,lo_freq_ref);
    }
    Activate_FSW_register_block_fm("FSW2");
    Hot_cold(band,hrs_mode,backend,total_time,"slowchop",0,0);
    //Look at the sky
    Chopper_Rotation_block_fm(band,"chop_hot_ang","chop_M3_ang");
    //Start integration in total power
    res = Configure_Spectrometer_AOTlike_proc_fm(band,integ_time,hrs_mode,backend);
    int phase_counter = 0;
    int phase_a_counter = 1;
    int phase_b_counter = 0;
    int nb_loop = nb_pairs * 2;
    bool modulate = true;
    while(phase_counter < nb_loop) {
        //First A-phase
        if(phase_counter < nb_loop) {
            if(phase_counter == 0) {
                modulate = true;
            } else {
                modulate = false;
            }
            Dip_FSW_A_phase(band,retune,lo_freq1,lo_freq_ref,[res[0],res[1]],backend,polarization,modulate);
            phase_a_counter = phase_a_counter + 1;
            phase_counter = phase_counter + 1;
            message("A1");
        }
        //Second A-phase if applicable
        if(phase_a_counter < 2 && phase_counter < nb_loop) {
            Dip_FSW_A_phase(band,retune,lo_freq1,lo_freq_ref,[res[0],res[1]],backend,polarization,true);
            phase_a_counter = phase_a_counter + 1;
            phase_counter = phase_counter + 1;
            message("A2");
        }
        //B-phase
        if(phase_counter < nb_loop) {
            Dip_FSW_B_phase(band,retune,lo_freq2,lo_freq_ref,[res[0],res[1]],backend,polarization,true);
            phase_b_counter = phase_b_counter + 1;
            phase_counter = phase_counter + 1;
            message("B1");
        }
        //Second B-phase if applicable
        if(phase_b_counter < 2 && phase_counter < nb_loop) {
            Dip_FSW_B_phase(band,retune,lo_freq2,lo_freq_ref,[res[0],res[1]],backend,polarization,false);
            phase_b_counter = phase_b_counter + 1;
            phase_counter = phase_counter + 1;
            message("B2");
        }
        //Closure A-phase
        if(phase_counter < nb_loop) {
            Dip_FSW_A_phase(band,retune,lo_freq1,lo_freq_ref,[res[0],res[1]],backend,polarization,true);
            phase_counter = phase_counter + 1;
            message("A2");
        }
        //Reset counters
        if(phase_counter % 4 == 0) {
            phase_a_counter = 1;
            phase_b_counter = 0;
        }
    }
    //Transfer delay before closing off observation
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = BackendSettings(band,0.0,hrs_mode,backend);
    int transfer = SlowChopReadoutDelay(band,lo_freq1,backendreadoutparms);
    delay(transfer);
}

/////////////////////////////////////
// Blocks
/////////////////////////////////////
// OBS SFT, block
block OBS_SFT_block_fm HIFI 3922 {
}{
    Start_block_no_hk_request();
    //Check PM memory
    //Applies to OBS 5.9.0
    int check_start = 0x5500;
    int check_end = 0x18435;
    int check_crc = 0x7b2e;
    Hifi_HIFI_check_PM_memory(check_start,check_end,check_crc);
    delay(3);
    //
    //Set Housekeeping rate to 1/sec
    Hifi_HIFI_Housekeeping_on("1_pkt_per_s","ON","ON","ON","ON","ON","ON");
    delay(1);
    //
    Hifi_HIFI_enable_time_verify();
    delay(1);
    //Simulate science: are the spectrometers automatically configured ?
    Hifi_HIFI_simulate_science();
    delay(30);
    //Should abort the above
    Hifi_HIFI_abort_spectroscopy();
    delay(1);
}

//HIFI-COP-1.2-FPU_FT
procedure FPU_FT_COP_proc_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b","8"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_comment("Start of HIFI FPU Functional Test for band " + band);
    mois_comment("Please ensure that instrument was switched on with the " + prime_or_redundant + " unit");
    //General parameters in use
    string hbb_heater = "ON";
    //hot source on/off
    string chopper_loop = "CLOSE";
    //
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    mois_step("Init of FPU");
    Init_MSA_ops(band,chopper_loop,lo_freq,result[0]{0},hbb_heater,prime_or_redundant);
    mois_tmcheck("Check content of ANDs FCU_H_device, FCU_V_device, FCU_PR_power and FPU_common with HIFI expert");
    //
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        mois_step("FPU heater test");
        Heater_fm(band);
    }
    //
}

// Compute the offset between two points
// This is an approximation for small offsets
{double,double} procedure AngularOffset {
    {double,double} vector1 = {0.0,0.0}; // First vector
    {double,double} vector2 = {0.2,0.2}; // Second vector
}{
    double pih = 3.14159265 / 2.0;
    double pideg = pih / 90.0;
    double l1 = vector1{0} * pideg;
    double b1 = vector1{1} * pideg;
    double l2 = vector2{0} * pideg;
    double b2 = vector2{1} * pideg;
    // 3-D vector
    double u1 = cos(b2) * cos(l2);
    double u2 = cos(b2) * sin(l2);
    double u3 = sin(b2);
    // Rotate by l1
    double s1 = cos(l1) * u1 + sin(l1) * u2;
    double s2 = -sin(l1) * u1 + cos(l1) * u2;
    double s3 = u3;
    // Rotate by b1
    u1 = cos(b1) * s1 + sin(b1) * s3;
    u2 = s2;
    u3 = -sin(b1) * s1 + cos(b1) * s3;
    // Extract angles
    double u12 = sqrt(u1 * u1 + u2 * u2);
    if(u12 > 0.0) {
        double db = atan(u3 / u12);
    } else {
        db = pih;
    }
    if(u1 != 0.0) {
        double dl = atan(u2 / u1);
    } else {
        dl = pih;
    }

    return {dl / pideg,db / pideg};
}

// Total noise from a symmetric two-phase observation
// This is still to be scaled by a factor 1.0/(B_fluct*T_obs)
double procedure TwoPhaseNoise {
    double x = 0.1; // value for integration time relative to Allan time
    double[] parameters = [0.3,2.5]; // Parameters: delay relative to Allan time, drift exponent 
}{
    // Assign parameters
    double d = parameters[0];
    double alpha = parameters[1];
    // add radiometric and drift noise
    double yn = TwoPhaseRadioNoise(x);
    double yd = TwoPhaseDrift(x,d,alpha);
    // Add and normalize with respect to total observing time
    double y = (yn + yd) * (2.0 * x + d);

    return y;
}

// FPU settling time for a mixer band change, 3rd block
// Block for third tuning
block FPU_Settling_time_third_tuning_fm HIFI 3685 {
    string band_1 = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    int int_time2 = 600; //Integration time after first and second switch
    double lo_freq_1 = 500.0; //LO frequency in sub-band a
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //
    //Init and tune of LO: configuration from safe to tuned.
    LCU_config_nominal_proc_fm(band_1,lo_freq_1);
    LO_tuning_w_mixerchoice_proc(band_1,lo_freq_1,"H");
    //
    //Configure spectroscopy integration
    Configure_Spectrometer_proc_fm(band_1,int_time2,["wb1","wb1"],backend);
    //4 sec. integration
    //Take series of spectra during int_time2 seconds
    HIFI_Spectr_total_power_proc_fm(band_1,backend,int_time2);
    //
    //Now switch off LO sub-band
    LCU_switch_off_proc_fm();
}

// Mode initialisation
procedure StartMode_no_hk_request {
}{
    BroadcastOBSID_no_hk_request();
    //Get applicable HK rate
    {double,string}[] result_d = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    double hk_rate = result_d[0]{0};
    //HKrate (hk_rate) ;
}

////////////////////////////////////////
// Standing wave analysis, procedure   NDW
// This is like a radiometry: 4 spectra
//  noretune version
procedure Standing_wave_noretune_fm {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    double[] lo_freq_input = [500.0,500.15,0.02]; //Start, end and step lo_freq for the LO scan
}{
    // Initial LO tuning at centre frequency of scan  (NDW)
    //
    double lo_freq_ref = (lo_freq_input[0] + lo_freq_input[1]) / 2.0;
    LO_tuning_block_fm(band,lo_freq_ref);
    double lo_freq = lo_freq_input[0];
    //
    //WBS calibration and backend tuning
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_stndwave_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration
    //Slowchop will be used for all bands - FSW no longer considered for HEBs
    //
    int[] res = [0,0];
    int total_time = 0;
    res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
    total_time = res[0] * res[1];
    //
    //Loop on LO frequencies. It is assumed that the LO is tuned at the middle frequency of the scan
    //
    while(lo_freq <= lo_freq_input[1]) {
        //
        //Set synthesizer to new LO freq.
        LCU_config_nominal_noretune_block_fm(band,lo_freq,lo_freq_ref);
        // NDW
        //
        //First internal loads
        Hot_cold(band,hrs_mode,backend,res[0] * res[1],"slowchop",0,0);
        //Then external loads - this will drop if not ILT-context
        //Hot_cold_external(band,res[0]*res[1],backend);
        //Increase lo_freq
        lo_freq = lo_freq + lo_freq_input[2];
    }
}

// convenience procedure for collecting 
// consecutive memory locations from an LCU memory patch file
// Also works for maxrunlength = 1
{int,int[]}[] procedure LcuGetMemoryRuns {
    string section = "P" in ["P","R"]; // select prime or redundant LCU
    int maxrunlength = 100 in [1,1000];
}{
    string tab = "LcuMemoryPatch_" + section + ".config";
    int total = table_size(tab);
    {int,int[]}[] result = [];
    int runcount = 0;
    int[] thisrun = [];
    int thisrunlength = 0;
    int startlocation = -1;
    for(int line = 1 .. total) {
        string look = "" + line;
        int loc = ilookup(tab,look,"location");
        int val = ilookup(tab,look,"value");
        bool samerun = loc == startlocation + 2 * thisrunlength;
        if(samerun && thisrunlength < maxrunlength) {
            thisrun[thisrunlength] = val;
            thisrunlength = thisrunlength + 1;
        } else {
            if(startlocation >= 0) {
                result[runcount] = {startlocation,thisrun};
                runcount = runcount + 1;
            }
            thisrun = [val];
            thisrunlength = 1;
            startlocation = loc;
        }
    }
    if(thisrunlength > 0) {
        result[runcount] = {startlocation,thisrun};
    }

    return result;
}

{int,double,double,double,double,double} obs HifiMappingModeLoadChopOTF {
    string modeName = "load-raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Mapping - OTF Map Load Chop Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,n_linesperscan,0,0,n_cycles,load_interval});
    // Auxiliary routine for API parameter correction
    {double,double,int} mapused = ValidMapSize(band,lo_freq,lineDistance,nlines,stepsize,npoints,2 * data_time * n_switch_on);
    double line_used = mapused{0};
    double scanvelocity = mapused{1};
    int npoints_used = mapused{2};
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int} pre_timing = OTFLoadChop_pre_timing(nlines,npoints_used,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_linesperscan,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,double,double,int,int,int,int,int} tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,pre_timing);
    // Dummy call to spacecraft command
    int[] telescopetimes = line_scan_with_off_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int},double,double} post_timing = OTFmap_post_timing(pre_timing,telescopetimes,data_time,n_linesperscan,n_cycles,load_interval);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,post_timing{1});
    // Call telescope command
    telescopetimes = line_scan_with_off_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int n_pp = post_timing{1}{0};
    int n_scans = post_timing{1}{1};
    int off_inttime = post_timing{1}{2};
    int loadlength = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{5};
    double tscan = post_timing{2};
    double tdead = post_timing{3};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        OTFLoadChop_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,npoints_used * n_switch_on,n_switch_off,nlines * n_cycles,n_linesperscan,n_loadinterval,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = OTFDoubleChop_deadtimes("lchop",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_linesperscan,n_pp,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = OTFLoadChop_noisecomputer(band,lo_freq,effResolution,oneGHzReference,nlines,data_time,n_switch_on,n_linesperscan,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    OTFDoubleChop_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints_used,n_switch_on,n_switch_off,n_scans,n_cycles,false,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//HIFI-COP-2.3-Param-Scan
procedure Parameter_Scan_COP_proc_ops {
    int index = 1 in [1,7]; // Test case index as of config_paramscan_COP.config
    int phase = 1 in [1,2]; //Measurement phase
    int integ_time = 4; //Integration time PER PHASE for the Tsys slowchop measurement  
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int m1_index = 1 in [1,5]; //Index of M1 value - only applicable is phase = 1. Index 1 is least negative
    int m2_index = 1 in [1,5]; //Index of M2 value - only applicable is phase = 1. Index 1 is least negative
    int bias_index = 1 in [1,3]; //Index of bias value - only applicable is phase = 2
    int imix_index = 1 in [1,3]; //Index of Imix value - only applicable is phase = 2
}{
    int start = time();
    //
    //Read all band+param to perform
    string tab = "config_paramscan_COP.config";
    int total = table_size(tab);
    double lo_freq = dlookup(tab,"" + index,"lofreq");
    string band = slookup(tab,"" + index,"band");
    double m1_min = dlookup(tab,"" + index,"m1_1");
    double m1_max = dlookup(tab,"" + index,"m1_2");
    double m1_step = dlookup(tab,"" + index,"m1_step");
    double m2_min = dlookup(tab,"" + index,"m2_1");
    double m2_max = dlookup(tab,"" + index,"m2_2");
    double m2_step = dlookup(tab,"" + index,"m2_step");
    double bias_min = dlookup(tab,"" + index,"bias_1");
    double bias_max = dlookup(tab,"" + index,"bias_2");
    double bias_step = dlookup(tab,"" + index,"bias_step");
    double imix_min = dlookup(tab,"" + index,"imix_1");
    double imix_max = dlookup(tab,"" + index,"imix_2");
    double imix_step = dlookup(tab,"" + index,"imix_step");
    double m1 = m1_max - double(m1_index - 1) * m1_step;
    double m2 = m2_max - double(m2_index - 1) * m2_step;
    double bias = bias_min + double(bias_index - 1) * bias_step;
    double imix = imix_min + double(imix_index - 1) * imix_step;
    //Implementation of SCR-2460: for the time being, M2 is fixed to its nominal value - no scan
    string name_configlcu = "name_configlcu_b";
    {double,string}[] result = ConfigurationReader(name_configlcu,["m2_v"],band,lo_freq);
    m2 = result[0]{0};
    //General parameters for spectroscopy
    string backend = "both";
    string chopmode = "slowchop";
    double sampling_rate = 3.0;
    //Sampling rate: 2 (2 HRS-H + 2 HRS-V), 4 (HRS-H + HRS-V, 2 HRS-H or 2 HRS-V) or 8 (1 HRS-H or 1 HRS-V) Hz
    double hrs_h_1 = 7.4;
    //Position in IF of HRS-H sub-band 1
    double hrs_h_2 = 7.4;
    //Position in IF of HRS-H sub-band 2
    double hrs_v_1 = 7.4;
    //Position in IF of HRS-V sub-band 1
    double hrs_v_2 = 7.4;
    //Position in IF of HRS-V sub-band 2
    double[] hrs_subband = [hrs_h_1,hrs_h_2,hrs_v_1,hrs_v_2];
    string hrs_polarization = "B";
    //HRS polarization: selection works only for 4 and 8 Hz
    int n = 1466;
    //Switch-on LO
    LCU_switchon_proc_fm(band);
    //Wait an extra delay of 1 min for short term stabilization
    delay(60);
    //
    //FPU configuration
    Init_MSA_HBB_fm(band,"CLOSE",lo_freq,"ON");
    //Phase 1 measurement: M1 and M2 pair
    if(phase == 1) {
        // 
        //Tune LO at standard target
        LO_tuning_w_M1M2_block_fm(band,lo_freq,m1,m2);
        message(band + ", " + lo_freq + ", " + m1 + ", " + m2);
        //
        //Tsys measurement
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
        HRS_tune_block_fm(band);
        //Configure spectroscopy for slowchop hotcold
        int[] res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
        int total_time = res[0] * res[1];
        Hot_cold(band,hrs_mode,backend,total_time,chopmode,0,0);
        //
        //HRS fast stability measurment
        Stability_fast_proc_fm(band,n,hrs_subband,sampling_rate,hrs_polarization);
        //
    }
    //Phase 2 measurement: bias and Imix pair
    if(phase == 2) {
        //Configure at nominal M1,M2 (i.e. they are in the LCU safety table release)
        LCU_config_nominal_proc_fm(band,lo_freq);
        message(band + ", " + lo_freq + ", " + bias + ", " + imix / 1000.0);
        //Apply biases
        //In case of band 6 or 7, go via max first
        if(band == "7b") {
            result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
            //First go to 4mV
            Mixerbias_block_fm(result[0]{0},result[1]{0});
            //Then to nominal
            Mixerbias_block_fm(bias,bias);
        }
        // 
        //Tune LO at dedicated target (use of H mixer)
        LO_tuning_w_targetC_block_fm(imix / 1000.0,band,lo_freq,"H");
        //
        //Tsys measurement
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
        HRS_tune_block_fm(band);
        //Configure spectroscopy for slowchop hotcold
        res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
        total_time = res[0] * res[1];
        Hot_cold(band,hrs_mode,backend,total_time,chopmode,0,0);
        //
        //HRS fast stability measurment
        Stability_fast_proc_fm(band,n,hrs_subband,sampling_rate,hrs_polarization);
        //
    }
}

////////////////////////////////////
// Mode status procedures: allow 
// spacon to check mode status at
// start and end from mode switch 
// procedure
////////////////////////////////////
//Dump 7AH page
block Dump_7AH_page_block_mois HIFI 3851 {
}{
    // BBID needs to be set manually as the main TC command has no BBID argument
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    delay(1);
    //
    //Hifi_HIFI_LCU_read_settings();
    delay(1);
    //
}

// Function allowing to derive HRS internal LO parameters A and M
// in function of requested frequencies.
//  - The first 4 IF are given in GHz between 4 and 8 GHz
//  - The 5th and 6th LOs (fixed) are given in GHz
//  - The 7th LO is given in MHz 
//
// The rules are:
//   - 64 <= M <= 84, 0 <= A <= 9
//   - Flo = 200x(M+1)+20xA
//     with Flo in 13-17.180 GHz, i.e. 9GHz above IF
//
// The result array is organized as follows:
// [A1_h,M1_H, A2_H,...A7_h,A1_v,M1_v,A2_v,..,A7_v]
//
// DT - 3 June 2005
int[] procedure ComputeA_M_parameters {
    string[] hrs_mode = ["wb","wb"]; //HRS resolution mode for both polar: hr, mr, lr, wb
    double hrh_up_ol1 = 4.5; // IF1 frequency for H-polar
    double hrh_up_ol2 = 4.5; // IF2 frequency for H-polar
    double hrh_up_ol3 = 4.5; // IF3 frequency for H-polar
    double hrh_up_ol4 = 4.5; // IF4 frequency for H-polar
    double hrh_down_ol5 = 10.5; // LO5 frequency for H-polar
    double hrh_down_ol6 = 1.25; // LO6 frequency for H-polar
    double hrh_down_ol7 = 490.0; // LO7 frequency for H-polar
    double hrv_up_ol1 = 4.5; // IF1 frequency for V-polar
    double hrv_up_ol2 = 4.5; // IF2 frequency for V-polar
    double hrv_up_ol3 = 4.5; // IF3 frequency for V-polar
    double hrv_up_ol4 = 4.5; // IF4 frequency for V-polar
    double hrv_down_ol5 = 10.5; // LO5 frequency for V-polar
    double hrv_down_ol6 = 1.25; // LO6 frequency for V-polar
    double hrv_down_ol7 = 490.0; // LO7 frequency for V-polar
}{
    //Initialize array
    //Defaults are: lo1=13, lo2=14, lo3=15, lo4=16 GHz
    int[] a_m_parameter = [0,64,0,64,0,64,0,64,5,51,0,49,7,0,64,0,64,0,64,0,64,5,51,0,49,7];
    int[] a_m = [0,0];
    //
    //The number of A and M parameters to compute depends on the mode
    //
    //First rename LO7 and convert to GHz
    double flo7_h = hrh_down_ol7 / 1000.0;
    double flo7_v = hrv_down_ol7 / 1000.0;
    //Initialize freq.
    double flo_u1_h = 0.0;
    double flo_u1_v = 0.0;
    double flo_l2_h = 0.0;
    double flo_l2_v = 0.0;
    double flo_u3_h = 0.0;
    double flo_u3_v = 0.0;
    double flo_l4_h = 0.0;
    double flo_l4_v = 0.0;
    //
    //Available sub-band width: as of SPR-2479
    double bw_h = flo7_h / 2.0 - 0.015;
    double bw_v = flo7_v / 2.0 - 0.015;
    //High-Resolution
    if(hrs_mode[0] == "hr") {
        //H-polar
        flo_u1_h = (9.25 - bw_h / 2.0 + hrh_up_ol1) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u1_h = Check_HRS_prohibited_LO_proc_fm(flo_u1_h);
        a_m = GetA_M(flo_u1_h);
        a_m_parameter[0] = a_m[0];
        a_m_parameter[1] = a_m[1];
    }
    //
    if(hrs_mode[1] == "hr") {
        //V-polar
        flo_u1_v = (9.25 - bw_v / 2.0 + hrv_up_ol1) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u1_v = Check_HRS_prohibited_LO_proc_fm(flo_u1_v);
        a_m = GetA_M(flo_u1_v);
        a_m_parameter[13] = a_m[0];
        a_m_parameter[14] = a_m[1];
    }
    //
    //Medium-Resolution
    if(hrs_mode[0] == "mr") {
        //H-polar
        flo_u1_h = (9.25 - bw_h / 2.0 + hrh_up_ol1) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u1_h = Check_HRS_prohibited_LO_proc_fm(flo_u1_h);
        a_m = GetA_M(flo_u1_h);
        a_m = GetA_M(flo_u1_h);
        a_m_parameter[0] = a_m[0];
        a_m_parameter[1] = a_m[1];
        flo_l4_h = (9.25 + bw_h / 2.0 + hrh_up_ol4) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_l4_h = Check_HRS_prohibited_LO_proc_fm(flo_l4_h);
        a_m = GetA_M(flo_l4_h);
        a_m_parameter[6] = a_m[0];
        a_m_parameter[7] = a_m[1];
    }
    //
    //Medium-Resolution
    if(hrs_mode[1] == "mr") {
        //V-polar
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u1_v = Check_HRS_prohibited_LO_proc_fm(flo_u1_v);
        flo_u1_v = (9.25 - bw_v / 2.0 + hrv_up_ol1) * 1000.0;
        a_m = GetA_M(flo_u1_v);
        a_m_parameter[13] = a_m[0];
        a_m_parameter[14] = a_m[1];
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_l4_v = Check_HRS_prohibited_LO_proc_fm(flo_l4_v);
        flo_l4_v = (9.25 + bw_v / 2.0 + hrv_up_ol4) * 1000.0;
        a_m = GetA_M(flo_l4_v);
        a_m_parameter[19] = a_m[0];
        a_m_parameter[20] = a_m[1];
    }
    //
    //Low-Resolution
    if(hrs_mode[0] == "lr") {
        //H-polar
        flo_u1_h = (9.25 - bw_h / 2.0 + hrh_up_ol1) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u1_h = Check_HRS_prohibited_LO_proc_fm(flo_u1_h);
        a_m = GetA_M(flo_u1_h);
        a_m_parameter[0] = a_m[0];
        a_m_parameter[1] = a_m[1];
        flo_l2_h = (9.25 + bw_h / 2.0 + hrh_up_ol2) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_l2_h = Check_HRS_prohibited_LO_proc_fm(flo_l2_h);
        a_m = GetA_M(flo_l2_h);
        a_m_parameter[2] = a_m[0];
        a_m_parameter[3] = a_m[1];
        flo_u3_h = (9.25 - bw_h / 2.0 + hrh_up_ol3) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u3_h = Check_HRS_prohibited_LO_proc_fm(flo_u3_h);
        a_m = GetA_M(flo_u3_h);
        a_m_parameter[4] = a_m[0];
        a_m_parameter[5] = a_m[1];
        flo_l4_h = (9.25 + bw_h / 2.0 + hrh_up_ol4) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_l4_h = Check_HRS_prohibited_LO_proc_fm(flo_l4_h);
        a_m = GetA_M(flo_l4_h);
        a_m_parameter[6] = a_m[0];
        a_m_parameter[7] = a_m[1];
    }
    //
    //Low-Resolution
    if(hrs_mode[1] == "lr") {
        //V-polar
        flo_u1_v = (9.25 - bw_v / 2.0 + hrv_up_ol1) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u1_v = Check_HRS_prohibited_LO_proc_fm(flo_u1_v);
        a_m = GetA_M(flo_u1_v);
        a_m_parameter[13] = a_m[0];
        a_m_parameter[14] = a_m[1];
        flo_l2_v = (9.25 + bw_v / 2.0 + hrv_up_ol2) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_l2_v = Check_HRS_prohibited_LO_proc_fm(flo_l2_v);
        a_m = GetA_M(flo_l2_v);
        a_m_parameter[15] = a_m[0];
        a_m_parameter[16] = a_m[1];
        flo_u3_v = (9.25 - bw_v / 2.0 + hrv_up_ol3) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u3_v = Check_HRS_prohibited_LO_proc_fm(flo_u3_v);
        a_m = GetA_M(flo_u3_v);
        a_m_parameter[17] = a_m[0];
        a_m_parameter[18] = a_m[1];
        flo_l4_v = (9.25 + bw_v / 2.0 + hrv_up_ol4) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_l4_v = Check_HRS_prohibited_LO_proc_fm(flo_l4_v);
        a_m = GetA_M(flo_l4_v);
        a_m_parameter[19] = a_m[0];
        a_m_parameter[20] = a_m[1];
    }
    //
    //Wide-Band
    if(hrs_mode[0] == "wb") {
        //H-polar
        flo_u1_h = (9.25 + hrh_up_ol1) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u1_h = Check_HRS_prohibited_LO_proc_fm(flo_u1_h);
        a_m = GetA_M(flo_u1_h);
        a_m_parameter[0] = a_m[0];
        a_m_parameter[1] = a_m[1];
        flo_l2_h = (9.25 + hrh_up_ol2) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_l2_h = Check_HRS_prohibited_LO_proc_fm(flo_l2_h);
        a_m = GetA_M(flo_l2_h);
        a_m_parameter[2] = a_m[0];
        a_m_parameter[3] = a_m[1];
        flo_u3_h = (9.25 + hrh_up_ol3) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u3_h = Check_HRS_prohibited_LO_proc_fm(flo_u3_h);
        a_m = GetA_M(flo_u3_h);
        a_m_parameter[4] = a_m[0];
        a_m_parameter[5] = a_m[1];
        flo_l4_h = (9.25 + hrh_up_ol4) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_l4_h = Check_HRS_prohibited_LO_proc_fm(flo_l4_h);
        a_m = GetA_M(flo_l4_h);
        a_m_parameter[6] = a_m[0];
        a_m_parameter[7] = a_m[1];
    }
    //
    //Wide-Band
    if(hrs_mode[1] == "wb") {
        //V-polar
        flo_u1_v = (9.25 + hrv_up_ol1) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u1_v = Check_HRS_prohibited_LO_proc_fm(flo_u1_v);
        a_m = GetA_M(flo_u1_v);
        a_m_parameter[13] = a_m[0];
        a_m_parameter[14] = a_m[1];
        flo_l2_v = (9.25 + hrv_up_ol2) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_l2_v = Check_HRS_prohibited_LO_proc_fm(flo_l2_v);
        a_m = GetA_M(flo_l2_v);
        a_m_parameter[15] = a_m[0];
        a_m_parameter[16] = a_m[1];
        flo_u3_v = (9.25 + hrv_up_ol3) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_u3_v = Check_HRS_prohibited_LO_proc_fm(flo_u3_v);
        a_m = GetA_M(flo_u3_v);
        a_m_parameter[17] = a_m[0];
        a_m_parameter[18] = a_m[1];
        flo_l4_v = (9.25 + hrv_up_ol4) * 1000.0;
        //Implement SCR-1243: 14.4 and 14.42 GHz not allowed
        flo_l4_v = Check_HRS_prohibited_LO_proc_fm(flo_l4_v);
        a_m = GetA_M(flo_l4_v);
        a_m_parameter[19] = a_m[0];
        a_m_parameter[20] = a_m[1];
    }
    //
    //Get LO5 to LO7
    //
    a_m = GetA_M(hrh_down_ol5 * 1000.0);
    a_m_parameter[8] = a_m[0];
    a_m_parameter[9] = a_m[1];
    a_m = GetA_M(hrv_down_ol5 * 1000.0);
    a_m_parameter[21] = a_m[0];
    a_m_parameter[22] = a_m[1];
    //
    //flo6 is 1.25, we use a trick here since the formula for lo6 is 25(M+1)+2.5A
    double flo6_h = hrh_down_ol6 + 8.75;
    double flo6_v = hrv_down_ol6 + 8.75;
    a_m = GetA_M(flo6_h * 1000.0);
    //should be 49,0
    a_m_parameter[10] = a_m[0];
    a_m_parameter[11] = a_m[1];
    a_m = GetA_M(flo6_v * 1000.0);
    //should be 49,0
    a_m_parameter[23] = a_m[0];
    a_m_parameter[24] = a_m[1];
    //
    a_m_parameter[12] = iround((flo7_h * 1000.0 - 350.0) / 20.0);
    //flo7 = 2(10(M+1)+A), A=5, M = M+16
    a_m_parameter[25] = iround((flo7_v * 1000.0 - 350.0) / 20.0);
    //So 490 MHz is M=7.
    //
    //debug_print("Tuning result " + a_m_parameter);

    return a_m_parameter;
}

// FPU Standby with chopper switched on and to be used for open-loop. 
// Ensures that chopper will be commanded to zero-position, block
block Band0_chopper_at_zero_block_fm HIFI 3296 {
    string band = "0"; // HIFI band
    string chop_loop = "CLOSE"; // Chopper Loop status
    string hbb_heater = "ON" in ["ON","OFF"]; //hot source on/off
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    if(hbb_heater == "ON") {
        result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,0.0);
        calibcurrent = result_d[0]{0};
    }
    //
    result_d = ConfigurationReader("name_confilfpu",["bias_standby_h","diplexer_standby_h","bias_standby_v","diplexer_standby_v","diplex_h_ctrl_mode","diplex_v_ctrl_mode","chop_M3right"],band,0.0);
    //
    double bias_H = result_d[0]{0};
    double diplex_H = result_d[1]{0};
    double bias_V = result_d[2]{0};
    double diplex_V = result_d[3]{0};
    int diplex_h_ctrl_mode = iround(result_d[4]{0});
    int diplex_v_ctrl_mode = iround(result_d[5]{0});
    //
    //Retrieve magnets Magnet are so far at maximum value. Now set to nominal
    double magnetcurrent_H = result_d[1]{0};
    double magnetcurrent_V = result_d[4]{0};
    //
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_standby_h","magnet_standby_v"],band,0.0);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],band,0.0);
    //Here we force to 0.0 even in CLOSE loop
    double chopper = 0.0;
    //result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
}

//Set LCU6Hb back to standby status, procedure
procedure LCU6Hb_standby_proc_fm {
    string band = "7b"; // HIFI band
    double lo_freq = 1800.0 in [1800.0,1900.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

// Spectra obtained with the mixer bias low in the resistive region
block Spectra_resistive_low_fm HIFI 3231 {
    string band = "1a";
    double bias_h = 0.0;
    double bias_v = 0.0;
    int integ_time = 4; //Total integration time in sec.: at least 2sec !  
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block() ; 
    Mixerbias(bias_h,bias_v);
    HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
    //
}

// Stability test, procedure
// Measurement of internal cold against internal hot
procedure Proc_stability_intcold_inthot {
    string band = "1a"; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total (co-added) integration time of a phase in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "slowchop" in ["slowchop","fastchop"]; //Whether to use slowchop or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    //
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //Look at HBB
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        //Configure and tune backends
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration after tuning: done later
    //Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    Stability_intcold_inthot_fm(band,n,integ_time,hrs_mode,backend,chopmode,chop_phase);
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
    //2 sec. integration
}

//Retune HIFI - keep magnet and backends
procedure HIFITuneFreqNoretune {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; //LO frequency 
}{
    // frequency setup, stored in FSW1 register
    LCU_config_nominal_noretune_block_aot(band,lo_freq / 1000.0,false);
    //
}

// Check constancy of magnet current across scan
procedure CheckSpectralScanRange {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // reference LO frequency in MHz
    double lo_freq_low = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
}{
    // The current implementation assumes that the magnet current does not
    // change within a spectral scan - to be sure I add a check
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        // first frequency
        {double,string}[] result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq / 1000.0);
        bool ok = true;
        double mxmg_h = result_d[0]{0};
        double mxmg_v = result_d[1]{0};
        // second frequency
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq_low / 1000.0);
        if(mxmg_h != result_d[0]{0} || mxmg_v != result_d[1]{0}) {
            ok = false;
        }
        // third frequency
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq_up / 1000.0);
        if(mxmg_h != result_d[0]{0} || mxmg_v != result_d[1]{0}) {
            ok = false;
        }
        if(!ok) {
            CError("Magnet field not constant across selected spectral scan range");
        }
    }
}

{int,double,double,double,double,double} obs HifiPointModeLoadChopNoRef {
    string modeName = "load";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_cycles = 2 in [1,3600]; // number of half load-sky-sky-load cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Single Point - Load Chop noRef",{data_time,0,0,0,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,bool,int,int} pre_timing_f = LoadChopNoRef_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_cycles,load_interval,docommands);
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,double,double,int} tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,pre_timing_f);
    // Dummy call to spacecraft command
    int[] telescopetimes = basic_fine_pointing(false,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,bool,int,int},double,double} post_timing_f = SingleChopNoRef_post_timing(pre_timing_f,telescopetimes);
    // Now the actual observation starts
    // Prepare telescope command
    tpar_f = Fine_telescope(naifid,onPosition,band,lo_freq,post_timing_f{1});
    // Call telescope command 
    telescopetimes = basic_fine_pointing(true,tpar_f{0},tpar_f{1},tpar_f{2},tpar_f{3},tpar_f{4},tpar_f{5},tpar_f{6},tpar_f{7},tpar_f{8},tpar_f{9});
    // Consistency check
    int totaltime = post_timing_f{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    //////////////////////////////////////////////////////////////////////
    // standard parameters for fine pointing
    int loadlength = post_timing_f{1}{2};
    int n_per_on = post_timing_f{1}{4};
    int n_load_on = post_timing_f{1}{5};
    bool end_load_on = post_timing_f{1}{6};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    //////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        LoadChopNoRef_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_per_on,n_load_on,end_load_on,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // There are no telescope dead times involved in this mode
    {double,double,double} tact = SingleChop_deadtimes("lchop",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_per_on);
    double tscan = 2.0 * (tact{1} + tact{2});
    double tdead = 2.0 * tact{2};
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = PositionSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_per_on * (n_load_on + 1),tscan,tdead);
    // Evaluate performance
    SingleChopNoRef_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_per_on * (n_load_on + 1),false,tscan,tdead);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//////////////////////////////////////////////////////////////////////////
// Procedure for telescope commanding is inherited from DBS mode
////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure SScanDBS_commanding {
    string band = "4a"; // HIFI band
    double reffreq = 978300.0; // Reference characteristic LO frequency 
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int grouplen = 1; // Number of frequency steps per nodding phase
    int[][] grouporder = [[0],[0]]; // Sequence to trace frequency points in both phases
    double[] freqgrid = [978053.7,978301.8,978381.1]; // Table of frequency points
    bool retuning = false; // need for WBS retuning
    double[] targetlevels = [1.0,1.0,1.0]; // WBS tuning levels
    int data_time = 4; // chunk size
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int allsteps = 4; // Total number of frequency pointing periods
    int n_bchop = 1; // Normal number of chop cycles per frequency and pointing
    int n_long = 1; // Chop cycles per frequency and pointing without retuning
    int n_loadinterval = 1; // number of nods before a load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
    int shiftlength = 10; // Shift of the loop start relative to the pointing
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int tnodslew = telescopetimes[2];
    // slew dead time between points
    // First frequency
    double runningfreq = freqgrid[grouporder[0][0]];
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,reffreq,backendreadoutparms);
    // recompute load duration for initial load measurement
    int loadlength = duration(SScanLoadMeasurement(band,runningfreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms));
    loadlength = loadlength + readoutdead;
    bool retuneload = n_loadinterval > 1;
    // Tuning levels
    string[] targetnames = TargetNames(band,reffreq,retuning,targetlevels);
    string target = targetnames[0];
    // All commands with a duration possibly depending on the frequency
    // are taken at the reference frequency to guarantee synchonization
    // Declare auxiliary variables to be used in the loops
    int i_freqcycles = 0;
    int i_group = 0;
    int i_phase = 0;
    // variables storing the configuration setting
    bool islong = false;
    bool isinvalid = true;
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Instrument Initialization:  The instrument tuning is done as early as
            // possible, the load calibration as late as possible
            //
            HIFIInitObs();
            TuneHIFI(band,runningfreq,hrs1,hrs2,wbs1{0},wbs2{0},target);
            delay(tinitslew - (time() - startobs) - loadlength + shiftlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            SScanLoadMeasurement(band,runningfreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms);
            if(shiftlength > 0) {
                runintostate = true;
            } else {
                runintostate = false;
            }
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            i_phase = (state[2] + 1) % 2;
            // Reset group counter
            i_group = 0;
            runintostate = false;
            // long integrations not possible in last and first nod cycle
            if(n_cycles > 1 && state[2] % n_cycles != state[2] % 2) {
                if(isinvalid || !islong) {
                    HIFIConfigureSlowChopIntegration(data_time,n_long,band,reffreq,backendreadoutparms);
                    islong = true;
                    isinvalid = false;
                }
                HIFISlowChopOnIntegration(data_time,n_long,band,reffreq,rates);
            } else {
                if(isinvalid || islong) {
                    HIFIConfigureSlowChopIntegration(data_time,n_bchop,band,reffreq,backendreadoutparms);
                    islong = false;
                    isinvalid = false;
                }
                while(i_group < grouplen - 1) {
                    HIFISlowChopOnIntegration(data_time,n_bchop,band,reffreq,rates);
                    // retune
                    i_group = i_group + 1;
                    runningfreq = freqgrid[grouporder[i_phase][i_group] + i_freqcycles * grouplen];
                    HIFIChangeFreq(band,runningfreq);
                }
                HIFISlowChopOnIntegration(data_time,n_bchop,band,reffreq,rates);
                // Now we switch to the next frequency group or repeat the cycle
                if(state[2] % n_cycles == 0 && i_phase == 1) {
                    // Big tuning step, but not at end of observation
                    if(state[2] < allsteps) {
                        i_freqcycles = i_freqcycles + 1;
                        runningfreq = freqgrid[grouporder[0][0] + i_freqcycles * grouplen];
                        target = targetnames[i_freqcycles];
                        HIFIRetuneFreq(band,runningfreq,target);
                        runintostate = true;
                    }
                }
            }
            // Active WBS HK if we have a nod slew without calibration
            if(state[2] % 2 == 1 && state[2] % n_loadinterval > 0) {
                HIFIActiveHK("normal",tnodslew);
            }
        }
        if(state[0] == 7) {
            // second nod position
            i_phase = state[2] % 2;
            // First nodding position
            // Reset group counter
            i_group = 0;
            runintostate = false;
            // long integrations not possible in last and first nod cycle
            if(n_cycles > 1 && state[2] % n_cycles != (state[2] % 2 + 1) % 2) {
                if(isinvalid || !islong) {
                    HIFIConfigureSlowChopIntegration(data_time,n_long,band,reffreq,backendreadoutparms);
                    islong = true;
                    isinvalid = false;
                }
                HIFISlowChopOffIntegration(data_time,n_long,band,reffreq,rates);
            } else {
                if(isinvalid || islong) {
                    HIFIConfigureSlowChopIntegration(data_time,n_bchop,band,reffreq,backendreadoutparms);
                    islong = false;
                    isinvalid = false;
                }
                while(i_group < grouplen - 1) {
                    HIFISlowChopOffIntegration(data_time,n_bchop,band,reffreq,rates);
                    // retune
                    i_group = i_group + 1;
                    runningfreq = freqgrid[grouporder[i_phase][i_group] + i_freqcycles * grouplen];
                    HIFIChangeFreq(band,runningfreq);
                }
                HIFISlowChopOffIntegration(data_time,n_bchop,band,reffreq,rates);
                // Now we switch to the next frequency group or repeat the cycle
                if(state[2] % n_cycles == 0 && i_phase == 1) {
                    // Big tuning step, but not at end of observation
                    if(state[2] < allsteps) {
                        i_freqcycles = i_freqcycles + 1;
                        runningfreq = freqgrid[grouporder[0][0] + i_freqcycles * grouplen];
                        target = targetnames[i_freqcycles];
                        HIFIRetuneFreq(band,runningfreq,target);
                        runintostate = true;
                    }
                }
            }
            // Active WBS HK if we have a nod slew without calibration
            if(state[2] % 2 == 0 && state[2] % n_loadinterval > 0) {
                HIFIActiveHK("normal",tnodslew);
            }
        }
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            SScanLoadMeasurement(band,runningfreq,reffreq,retuneload,eff_resolution{0},data_time,backendreadoutparms);
            isinvalid = true;
            runintostate = false;
        }
        if(state[0] == 5) {
            // The instrument stops halftunelength before the telescope
            // but I have to wait to close the observation
            HIFICloseObs();
        }
    }
}

{string,double,double}[] procedure HifiMappingModeLoadChopOTFSequencerInit {
    string modeName = "load-raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    {double,double,double,double} phaselengths = LoadChopPhaseLengths(band,lo_freq,effResolution,oneGHzReference);
    // Compute derived quantities
    // Main loop
    int main_phase = iceil(phaselengths{0});
    // How many lines could we do at most?
    int n_linesperscan_guess = main_phase / (2 * datalimit) + 1;
    n_linesperscan_guess = imax(n_linesperscan_guess * n_linesperscan_guess / npoints,1);
    // restrict the scan size
    if(nlines == 1 && n_linesperscan_guess > 1) {
        n_linesperscan_guess = 2;
    } else {
        n_linesperscan_guess = IMultiple(n_linesperscan_guess,nlines);
        n_linesperscan_guess = imin(n_linesperscan_guess,nlines);
    }
    int n_linesperscan_range = 1 - n_linesperscan_guess;
    if(n_linesperscan_range == 0) {
        n_linesperscan_range = 1;
    }
    double n_pointsperscan = double(n_linesperscan * npoints);
    // Compute back
    int int_time_guess = main_phase / iceil(sqrt(n_pointsperscan));
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int n_switch_on_guess = imax(int_time_guess / (2 * data_time_guess),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    data_time_guess = imax(imin(5,int_time_guess / (2 * n_switch_on_guess)),datalimit);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) * 0.67 * sqrt(n_pointsperscan) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)},{"n_linesperscan",double(n_linesperscan_guess),double(n_linesperscan_range)}];

    return retvalues;
}

//TM check when in standby I
procedure Mode_status_check_standby_I {
    string chopper_loop = "OPEN" in ["OPEN","CLOSE"]; //chopper loop status
    string sequence_order = "up" in ["down","up"]; //order in which sequence is done
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_comment("Checking instrument status in standby I mode");
    //General checks: only done when going from intermediate
    if(sequence_order == "up") {
        mois_tmcheck("Check that the HK parameter HI_FCU_S, HI_WBSH_S, HI_WBSV_S, HI_HRSH_S, HI_HRSV_S and HI_LCU_S are all ON.");
    }
    //FCU checks: only done when going from intermediate
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],"0",0.0);
    double calibcurrent = result_d[0]{0};
    if(sequence_order == "up") {
        mois_tmcheck("Check that parameter HF_DH1_MXBAND and HF_DV1_MXBAND are both 0");
        mois_tmcheck("Check that parameter HF_APR_CS_C is set to " + calibcurrent + " mA. If not, you can proceed but need to inform the HIFI ICC.");
        mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to " + chopper_loop);
    }
    //Chopper voltage
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    result_d = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    if(chopper_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],"0",0.0);
    }
    if(sequence_order == "up") {
        mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to " + result_d[0]{0});
    }
    //WBS checks
    result_d = ConfigurationReader("name_configwbs",["hwh_latchup_s","hwv_latchup_s"],"0",0.0);
    string hwh_latchup_s = "Low";
    if(result_d[0]{1} == "Level2") {
        hwh_latchup_s = "High";
    }
    string hwv_latchup_s = "Low";
    if(result_d[1]{1} == "Level2") {
        hwv_latchup_s = "High";
    }
    mois_tmcheck("Check that parameters HWH_Laser1_S, HWH_Laser2_S, HWV_Laser1_S and HWV_Laser2_S are all OFF");
    if(sequence_order == "up") {
        mois_tmcheck("Check that both parameters HWH_Zero_S and HWV_Zero_S are ON");
        mois_tmcheck("Check that both parameters HWH_Comb_S and HWV_Comb_S are OFF");
        mois_tmcheck("Check that parameters HWH_LUP_level_S and HWV_LUP_level_S are " + hwh_latchup_s + " and " + hwv_latchup_s + " respectively");
        mois_tmcheck("Check that parameter HWH_IN_ATT is set to 15, and parameters HWH_Band_1_ATT, HWH_Band_2_ATT, HWH_Band_3_ATT, HWH_Band_4_ATT are set to 7");
        mois_tmcheck("Check that parameter HWV_IN_ATT is set to 15, and parameters HWV_Band_1_ATT, HWV_Band_2_ATT, HWV_Band_3_ATT, HWV_Band_4_ATT are set to 7");
    }
    //HRS Checks: HRS only modified if from intermediate to standbyI
    if(sequence_order == "up") {
        // Fetch HRS configuration parameters
        //===================================
        //H-polar
        string hrs_filename_h = "name_confighrs_wb";
        {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_up_ol1","hrh_up_ol2","hrh_up_ol3","hrh_up_ol4","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],"0",0.0);
        string hrs_polarization_h = result[0]{1};
        double[] hrsH_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
        //V-polar
        string hrs_filename_v = "name_confighrs_wb";
        result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_up_ol1","hrv_up_ol2","hrv_up_ol3","hrv_up_ol4","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],"0",0.0);
        string hrs_polarization_v = result[0]{1};
        double[] hrsV_LO = [result[9]{0},result[10]{0},result[11]{0},result[12]{0},result[13]{0},result[14]{0},result[15]{0}];
        //
        mois_tmcheck("Check that parameters HRH_1U_ATT, HRH_1L_ATT, HRH_2U_ATT, HRH_2L_ATT, HRH_3U_ATT, HRH_3L_ATT, HRH_4U_ATT and HRH_4L_ATT are set to 15.5");
        mois_tmcheck("Check that parameters HRV_1U_ATT, HRV_1L_ATT, HRV_2U_ATT, HRV_2L_ATT, HRV_3U_ATT, HRV_3L_ATT, HRV_4U_ATT and HRV_4L_ATT are set to 15.5");
        mois_tmcheck("Check that parameters HRH_LOCK_LO1_S, HRH_LOCK_LO2_S, HRH_LOCK_LO3_S, HRH_LOCK_LO4_S, HRH_LOCK_LO5_S, HRH_LOCK_LO6_S, and HRH_LOCK_LO7_S are all Locked");
        mois_tmcheck("Check that parameters HRV_LOCK_LO1_S, HRV_LOCK_LO2_S, HRV_LOCK_LO3_S, HRV_LOCK_LO4_S, HRV_LOCK_LO5_S, HRV_LOCK_LO6_S, and HRV_LOCK_LO7_S are all Locked");
        Check_HRS_LO_proc_ops(["wb","wb"],hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],hrsH_LO[4],hrsH_LO[5],hrsH_LO[6],hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],hrsV_LO[4],hrsV_LO[5],hrsV_LO[6]);
    }
    //LOU Checks: first time to check LOU HK when coming from intermediate
    if(sequence_order == "up") {
        mois_tmcheck("Check that parameter HL_MODE_S is standby");
        mois_tmcheck("Check that parameter HL_Channel_S is Off");
    }
}

// Get maximum delay needed for backend readout after FastChopSpectroscopy
int procedure FastChopReadoutDelay {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{true,1,[true,true,true,true]},{true,1,[true,true,true,true]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]},{true,[[0,2048],[0,2048],[0,2048],[0,2048]]}}; // HRS1/2 {used,resolution,subbands used}, WBS1/2 {used, channel windows}
}{
    // Currently the delay applies independent from the spectrometer selection
    // if (backendreadoutparms{2}{0} || backendreadoutparms{3}{0}) {
    double[] dead = CalibrationReader("fastchopreadout",["fastchopreadout"],band,lo_freq);
    // }

    return iceil(dead[0]);
}

// Equivalent procedure for the nodding_of_raster pointing mode
{int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,double,double,int,int,int,int,int} procedure DBSMultiRaster_telescope {
    int naifid = 0; // Tracing object ID
    {double,double} mapcenter = {0.0,0.0}; // Coordinates of the center of the map
    {double,double} linedistance = {0.0050,0.0050}; // Distance between subsequent rows
    double stepsize = 0.0050; // Distance between subsequent points in the raster line
    int nlines_tot = 1; // Number of rows in the map;
    int npoints = 10; // Number of points per row 
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    string throw = ""; // Identifier for chop throw, empty is standard
    {int,int,int,int,int,int,int,int,int,int,int,int,int} timing = {4,10,4,21,1,1800,0,10,1,1,1,50,0}; // full timing parameter list  
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF pointing cycles
}{
    // Assign values
    int pointing = timing{1};
    int loadlength = timing{3};
    int n_loadinterval = timing{7};
    int n_pointsperscan = timing{10};
    int initlength = timing{11};
    int dangling = timing{12};
    // Create variables for telescope command
    string ib = GetBoresight(band,lo_freq,true);
    // A change of ra-dec depending on naifid may be needed
    double ra = mapcenter{0};
    double dec = mapcenter{1};
    double patt = AngleFromVector(linedistance);
    patt = RotateRight(patt);
    // Pattern angle and throw of the chopper direction
    // The nodding angle should always be parallel to the chopper
    double[] chopper = GetSkyChopThrow(band,lo_freq,throw);
    double nodlength = chopper[0];
    double pattnod = chopper[1];
    nodlength = max(nodlength * 3600.0,2.0);
    // Map always in sky coordinates, 
    // (nod is always in instrument coordinates by default)
    bool fixed = true;
    // Map parameters
    double rowstep = 0.5 / 3600.0;
    double d1 = double(iceil(stepsize / rowstep)) * rowstep * 3600.0;
    double linestep = 0.5 / 3600.0;
    double d2 = AngleVectorLength(linedistance);
    d2 = double(iceil(d2 / linestep)) * linestep * 3600.0;
    // Exception for the "impossible" case of spacings below 2arcsec
    d1 = max(d1,2.0);
    d2 = max(d2,2.0);
    // no load slew if period too long
    if(n_loadinterval > npoints * nlines_tot * n_cycles / n_pointsperscan) {
        n_loadinterval = 0;
    }
    // Check parameter compatibility with pointing command for parameters
    // which are no direct input parameters
    if(pointing < 10) {
        SError("Pointing phase length too short. Increase the number of integrations.");
    }
    if(nodlength > 960.0) {
        IError("Nodding length too long. Choose a smaller chop throw.");
    }
    if(d1 > 480.0) {
        IError("Raster point spacing too coarse. Increase the sampling.");
    }
    if(d2 > 480.0) {
        IError("Raster line spacing too coarse. Increase the sampling.");
    }
    // repetition at multiple frequencies not yet implemented:
    int trep = 0;
    int n_repeat = 1;
    // return parameters in required order

    return {initlength,0,dangling,ib,naifid,ra,dec,fixed,patt,0.0,0.0,npoints,nlines_tot,d1,d2,pointing,trep,pattnod,nodlength,n_cycles,n_pointsperscan,n_repeat,loadlength,n_loadinterval};
}

// LO settling time for a LO sub-band change, 3rd block
// Block for third tuning
block LO_Settling_time_third_tuning_fm HIFI 3682 {
    string band_a = "1a" in ["1a","2a","3a","4a","5a","6a","7a"]; // HIFI band a
    int int_time2 = 600; //Integration time after first and second switch
    double lo_freq_a = 500.0; //LO frequency in sub-band a
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block();
    //
    //Init and tune of LO: configuration from safe to tuned.
    LCU_config_nominal_proc_fm(band_a,lo_freq_a);
    LO_tuning_w_mixerchoice_proc(band_a,lo_freq_a,"H");
    //
    //Configure spectroscopy integration
    Configure_Spectrometer_proc_fm(band_a,int_time2,["wb1","wb1"],backend);
    //4 sec. integration
    //Take series of spectra during int_time2 seconds
    HIFI_Spectr_total_power_proc_fm(band_a,backend,8);
    //
    //Now switch off LO sub-band
    LCU_switch_off_proc_fm();
}

// Switch HIFI off, block
// Prime and Redundancy are both called, regardless of which is effectively used
//
block HIFI_global_switch_off_block_ops HIFI 7921 {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    StartBlock_ops();
    //Sequentially notify PDU off then switch off S/S
    //
    //LOU
    string lo_subsys = "LO_Prime";
    string icu_subsys = "ICU_Prime";
    if(prime_or_redundant == "Red") {
        lo_subsys = "LO_Red";
        icu_subsys = "ICU_Red";
    }
    mois_step("Switch OFF LO S/S");
    HIFI_notify_PDU_status_off_proc_ops("ON","OFF","ON","ON","ON","ON");
    PDU_switch_off_proc_ops(lo_subsys);
    //WBS-H
    mois_step("Switch OFF WBS-H S/S");
    HIFI_notify_PDU_status_off_proc_ops("ON","OFF","ON","OFF","ON","ON");
    PDU_switch_off_proc_ops("WBS_H");
    //WBS-V
    mois_step("Switch OFF WBS-V S/S");
    HIFI_notify_PDU_status_off_proc_ops("ON","OFF","OFF","OFF","ON","ON");
    PDU_switch_off_proc_ops("WBS_V");
    //HRS-H
    mois_step("Switch OFF HRS-H S/S");
    HIFI_notify_PDU_status_off_proc_ops("ON","OFF","OFF","OFF","ON","OFF");
    PDU_switch_off_proc_ops("HRS_H");
    //HRS-V
    mois_step("Switch OFF HRS-V S/S");
    HIFI_notify_PDU_status_off_proc_ops("ON","OFF","ON","OFF","OFF","OFF");
    PDU_switch_off_proc_ops("HRS_V");
    //ICU
    mois_step("Switch OFF DPU and FCU S/S");
    HIFI_notify_PDU_status_off_proc_ops("OFF","OFF","OFF","OFF","OFF","OFF");
    PDU_switch_off_proc_ops(icu_subsys);
    //At that stage, the instrument is idle...
    mois_tmcheck("No telemetry should be received anymore from HIFI.");
}

// Switch HIFI off, procedure
// Prime and Redundancy are both called, regardless of which is effectively used
//
procedure HIFI_global_switch_off_proc_ops {
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //Sequentially notify PDU off then switch off S/S
    //
    //LOU
    string lo_subsys = "LO_Prime";
    string icu_subsys = "ICU_Prime";
    if(prime_or_redundant == "Red") {
        lo_subsys = "LO_Red";
        icu_subsys = "ICU_Red";
    }
    mois_step("Switch OFF LO S/S");
    HIFI_notify_PDU_status_off_block_ops("ON","OFF","ON","ON","ON","ON");
    PDU_switch_off_block_ops(lo_subsys);
    //WBS-H
    mois_step("Switch OFF WBS-H S/S");
    HIFI_notify_PDU_status_off_block_ops("ON","OFF","ON","OFF","ON","ON");
    PDU_switch_off_block_ops("WBS_H");
    //WBS-V
    mois_step("Switch OFF WBS-V S/S");
    HIFI_notify_PDU_status_off_block_ops("ON","OFF","OFF","OFF","ON","ON");
    PDU_switch_off_block_ops("WBS_V");
    //HRS-H
    mois_step("Switch OFF HRS-H S/S");
    HIFI_notify_PDU_status_off_block_ops("ON","OFF","OFF","OFF","ON","OFF");
    PDU_switch_off_block_ops("HRS_H");
    //HRS-V
    mois_step("Switch OFF HRS-V S/S");
    HIFI_notify_PDU_status_off_block_ops("ON","OFF","ON","OFF","OFF","OFF");
    PDU_switch_off_block_ops("HRS_V");
    //ICU
    mois_step("Switch OFF DPU and FCU S/S");
    HIFI_notify_PDU_status_off_block_ops("OFF","OFF","OFF","OFF","OFF","OFF");
    //If we want to have a chance to switch obsid/bbid to 0, it is here the
    //last opportunity
    StopMode_block_ops();
    //Finally, switch off ICU
    PDU_switch_off_block_ops(icu_subsys);
    //At that stage, the instrument is idle...
    mois_tmcheck("No telemetry should be received anymore from HIFI.");
}

/////////////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the OTF observing mode
{double,double,double,double,double} procedure OTFLoadChop_noisecomputer {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    int nlines_tot = 1; // Number of rows in the map
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int n_switch_on = 1; // Supersamplingfactor
    int n_linesperscan = 2; // Number of lines between two OFFs
    int off_inttime = 16; // Integration time per OFF phase
    int n_cycles = 1; // Number of map coverages
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double,double,double} tact = {10.0,4.9,4.9,0.05,0.05}; // Field of actual dead and integration times
}{
    // The sum of drift noise and radiometric noise is computed.
    //
    double tdead = tact{0};
    // Average total dead time in one scan
    double inttimeperonphase = tact{1};
    // Actual integration time in ON phase
    double inttimeperoffphase = tact{2};
    // Actual integration time in OFF phase
    double deadtimeperonphase = tact{3};
    // Dead time per switch phase on ON
    // Get parameters which are needed
    double tsys = InterpolateTsys(band,lo_freq);
    double eta_mb = InterpolateCoupling(band,lo_freq);
    double[] gssb = InterpolateGssb(band,lo_freq);
    // Get the drift parameters to compute the drift noise
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double allan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // Differential Allan variance
    allanparms = InterpolateSpecLChopAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double dalpha = allanparms[1];
    binningexp = 1.0 / allanparms[2];
    double dallan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double dallan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // resolution of OFF phase
    double sw_resolution = GetLoadChopSWResolution(band,lo_freq);
    double sw_resolution_lores = max(eff_resolution{1},sw_resolution);
    double sw_resolution_hires = max(eff_resolution{0},sw_resolution);
    // !!!! The computation of the noise is formally NOT CORRECT for this 
    // !!!! case. For simplicity we use as a rough approximations the equations
    // !!!! for a double-difference setup instead of a difference with 
    // !!!! OTF scheme !!!
    // Compute the relative noise for the detailed timing
    double on_int = double(2 * data_time * n_switch_on);
    // correct for double scan - treat like integrated in one go
    if(nlines_tot == 1 && n_linesperscan > 1) {
        on_int = on_int * double(n_linesperscan);
    }
    // fudge factor to taking OFF interpolation into account
    double off_int = double(off_inttime) * 1.5;
    // The dead time per switch might deviate between ON and OFF - ignored
    double deadtimeperswitch = deadtimeperonphase;
    // Dead time includes other points, but excludes off_int fudging
    // This is slightly too small (excludes inner point dead time) - ignored
    double tdiff = max(tscan - on_int - off_int,0.0);
    // Get actual noise
    // This is returned twice: for both limiting resolutions
    double systemnoise_lores = DoubleDifferenceNoise(inttimeperonphase / allan_time_lores,[inttimeperoffphase / inttimeperonphase,sw_resolution_lores / eff_resolution{1},on_int / allan_time_lores,off_int / allan_time_lores,deadtimeperswitch / allan_time_lores,tdiff / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    double systemnoise_hires = DoubleDifferenceNoise(inttimeperonphase / allan_time_hires,[inttimeperoffphase / inttimeperonphase,sw_resolution_hires / eff_resolution{0},on_int / allan_time_hires,off_int / allan_time_hires,deadtimeperswitch / allan_time_hires,tdiff / allan_time_hires,alpha,dallan_time_hires / allan_time_hires,dalpha]);
    double noiseratio = DoubleDifferenceNoiseRatio(inttimeperonphase / allan_time_lores,[inttimeperoffphase / inttimeperonphase,sw_resolution_lores / eff_resolution{1},on_int / allan_time_lores,off_int / allan_time_lores,deadtimeperswitch / allan_time_lores,tdiff / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    // Compute total double sideband noise 
    double dsbnoise_lores = tsys * sqrt(systemnoise_lores / (eff_resolution{1} * 1000000.0 * double(n_cycles) * tscan));
    double dsbnoise_hires = tsys * sqrt(systemnoise_hires / (eff_resolution{0} * 1000000.0 * double(n_cycles) * tscan));
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Get single sideband noise equivalent
    double usbnoise_lores = dsbnoise_lores / gssb[0];
    double usbnoise_hires = dsbnoise_hires / gssb[0];
    double lsbnoise_lores = dsbnoise_lores / gssb[1];
    double lsbnoise_hires = dsbnoise_hires / gssb[1];
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiseratio};
}

// FPU Standby with chopper switched on.
// Ensures that chopper will be commanded to zero-position, block
block Band0_chopper_at_zero_block_ops HIFI 7296 {
    string band = "0"; // HIFI band
    string chop_loop = "CLOSE"; // Chopper Loop status
    string hbb_heater = "ON" in ["ON","OFF"]; //hot source on/off
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //StartBlock_ops();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //  
    double calibcurrent = result_d[7]{0};
    if(hbb_heater == "ON") {
        result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,0.0);
        calibcurrent = result_d[0]{0};
    }
    //
    result_d = ConfigurationReader("name_confilfpu",["bias_standby_h","diplexer_standby_h","bias_standby_v","diplexer_standby_v","diplex_h_ctrl_mode","diplex_v_ctrl_mode","chop_M3right"],band,0.0);
    //
    double bias_H = result_d[0]{0};
    double diplex_H = result_d[1]{0};
    double bias_V = result_d[2]{0};
    double diplex_V = result_d[3]{0};
    int diplex_h_ctrl_mode = iround(result_d[4]{0});
    int diplex_v_ctrl_mode = iround(result_d[5]{0});
    double chopper = 0.0;
    //
    //Retrieve magnets Magnet are so far at maximum value. Now set to nominal
    double magnetcurrent_H = result_d[1]{0};
    double magnetcurrent_V = result_d[4]{0};
    //
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_standby_h","magnet_standby_v"],band,0.0);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    if(prime_or_redundant == "Prime") {
        Hifi_HIFI_P_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    } else {
        Hifi_HIFI_R_Configure_FCU($BBID,band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    }
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    Hifi_HIFI_non_periodic_hk_FCU();
    //
    //mois_tmcheck("Check that parameter HF_APR_CS_C is set to " + calibcurrent + " mA");
    //mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to " + chop_loop);
    mois_tmcheck("Check that parameter HF_DPR_CHSINE_S is set to " + chop_sine_s);
    //
}

//Slow chop between sky and Sky, block
block Sky_Sky_fm_COP HIFI 3927 {
    string band = "1a";
    int integ_time = 4; //Total integration time for delay computation
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,etc
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast 
}{
    //Fetch respective chopper angles
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_M3left","chop_M3right"],band,0.0);
    double chop_M3left = result[0]{0};
    double chop_M3right = result[1]{0};
    //
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"slowchop",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    HIFI_Spectr_slow_chop_proc_fm(chop_M3left,chop_M3right);
    Apply_Slow_Chop_delay(integ_time,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// Receiver gain and noise
procedure Hot_cold {
    string band = "1a"; // HIFI band
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,etc
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast 
    int integ_time = 4; //Total integration time per load integration in sec
    string chopmode = "tp" in ["tp","slowchop","fastchop","fsw"]; //modulation mode between hot/cold: tp, slowchop, fastchop
    int n_wbs1 = 20;
    int n_hrs_trans = 1;
}{
    if(chopmode == "tp") {
        Hot_spectra_fm(band,integ_time,backend);
        Cold_spectra_fm(band,integ_time,backend);
    }
    if(chopmode == "slowchop") {
        Hot_cold_slowchop_fm(band,integ_time,hrs_mode,backend);
    }
    if(chopmode == "fsw") {
        Hot_cold_FSW_fm(band,integ_time,backend);
    }
    if(chopmode == "fastchop") {
        Hot_cold_fastchop_fm(band,integ_time,hrs_mode,backend,n_wbs1,n_hrs_trans);
    }
}

//HIFI-COP-3-Stab-1
//This one should only be used for preparation of MOIS files
//for MOC. It assumes one single obsid for several frequencies
//This is not the default approach - see rather HifiEng_Stab_COP
mode HifiManCmd_Stab_COP_MOIS {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string stab = "sys" in ["sys","lsw","int","dbs","fsw","stab"]; //category of stability measurement
}{
    //
    StartMode_block_ops();
    //Allow fast HK readout
    HKrate_block_ops(1.0);
    //
    double band_nb = GetBandCode(band);
    //General parameters in use
    string backend = "both";
    string[] hrs_mode = ["wb1","wb1"];
    int[] res = [0,0];
    int n_wbs1 = 0;
    int n_hrs_trans = 0;
    string chopmode = "slowchop";
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //
    int integ_time = 4;
    int n = 900;
    double chop_phase = 1.0;
    string shutter = "open";
    //
    //Get the list of frequencies to be used for the scan
    string tab = "config_stabfreq_" + band + ".config";
    int total = table_size(tab);
    double stabfreq = 0.0;
    int time_systab = 0;
    int time_stabil = 20;
    //
    if(stab == "stab") {
        //
        stabfreq = dlookup(tab,"1","freq_sys");
        Init_MSA_HBB_fm(band,"CLOSE",stabfreq,"ON");
        //
        LCU_switchon_proc_fm(band);
        //
        LO_tuning_block_fm(band,stabfreq);
        HRS_config_block_fm(band,hrs_mode);
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
        HRS_tune_block_fm(band);
        //
        chopmode = "tp";
        n = time_stabil * 60 / integ_time + 1;
        // 
        Proc_stability_intcold(band,n,hrs_mode,integ_time,backend,chopmode,chop_phase);
    }
    //
    //start loop on frequencies
    for(int j = 1 .. total) {
        if(stab != "stab") {
            stabfreq = dlookup(tab,"" + j,"freq_" + stab);
        }
        time_systab = iround(dlookup(tab,"" + j,"tsystab"));
        //Only deal with non-zero entries
        if(stabfreq != 0.0) {
            //
            if(stab == "int") {
                n = 450;
                //     
                Init_MSA_HBB_fm(band,"CLOSE",stabfreq,"ON");
                LO_tuning_block_fm(band,stabfreq);
                WBS_calib_fm(band);
                WBS_tune_proc_fm(band);
                HRS_tune_block_fm(band);
                // 
                Proc_stability_intcold_inthot(band,n,hrs_mode,integ_time,backend,chopmode,chop_phase);
            }
            //
            if(stab == "lsw") {
                n = 450;
                //     
                Init_MSA_CBB_fm(band,"CLOSE",stabfreq,"ON");
                LO_tuning_block_fm(band,stabfreq);
                WBS_calib_fm(band);
                WBS_tune_proc_fm(band);
                HRS_tune_block_fm(band);
                // 
                Proc_stability_intcold_exthot(band,n,hrs_mode,integ_time,backend,chopmode,chop_phase);
            }
            //
            if(stab == "sys") {
                //Start with 4min fast HRS sampling
                double sampling_rate = 3.0;
                //Sampling rate: 2 (2 HRS-H + 2 HRS-V), 3 (HRS-H + HRS-V),  4 (2 HRS-H or 2 HRS-V) or 6 (1 HRS-H or 1 HRS-V) Hz
                double hrs_h_1 = 7.4;
                //Position in IF of HRS-H sub-band 1
                double hrs_h_2 = 7.4;
                //Position in IF of HRS-H sub-band 2
                double hrs_v_1 = 7.4;
                //Position in IF of HRS-V sub-band 1
                double hrs_v_2 = 7.4;
                //Position in IF of HRS-V sub-band 2
                double[] hrs_subband = [hrs_h_1,hrs_h_2,hrs_v_1,hrs_v_2];
                string hrs_polarization = "B";
                //HRS polarization: selection works only for 4 and 8 Hz
                n = 950;
                backend = "hrs";
                //     
                Init_MSA_HBB_fm(band,"CLOSE",stabfreq,"ON");
                LO_tuning_block_fm(band,stabfreq);
                // 
                if(band_nb > 10.0) {
                    Stability_fast_proc_fm(band,n,hrs_subband,sampling_rate,hrs_polarization);
                }
                //
                chopmode = "tp";
                n = time_systab * 60 / integ_time;
                // 
                HRS_config_block_fm(band,hrs_mode);
                WBS_calib_fm(band);
                WBS_tune_proc_fm(band);
                HRS_tune_block_fm(band);
                Proc_stability_intcold(band,n,hrs_mode,integ_time,backend,chopmode,chop_phase);
            }
            //
            if(stab == "fsw") {
                chopmode = "fsw";
                n = 225;
                //     
                Init_MSA_SKY_fm(band,"CLOSE",stabfreq,"ON");
                LO_tuning_block_fm(band,stabfreq);
                WBS_calib_fm(band);
                WBS_tune_proc_fm(band);
                HRS_tune_block_fm(band);
                // 
                //For FSW, there is an additional loop on various throws
                //Retrieve frequency throws from LUT
                string tabfsw = "config_freqthrow.config";
                double bandnb = GetBandCode(band);
                double[] freq_throw = [];
                for(int i = 1 .. 4) {
                    freq_throw[i] = dlookup(tabfsw,"" + iceil(bandnb),"freq_throw_" + i);
                    bool do_test = true;
                    if(j > 2 && i > 1) {
                        do_test = false;
                    }
                    if(freq_throw[i] != 0.0 && do_test) {
                        //Check that frequencies to switch are not far by more than 1 index
                        Check_FSW_index_proc_fm(band,stabfreq - freq_throw[i] / 2000.0,stabfreq + freq_throw[i] / 2000.0);
                        Proc_stability_freqswitch(band,stabfreq,freq_throw[i],n,hrs_mode,integ_time,backend);
                    }
                    //For one freq. in 1a, 3a, 6a and 7b, the FSW on the CBB is performed
                    string tabfswcbb = "config_stabfreq_fsw_CBB.config";
                    double fsw_cbb_freq = dlookup(tabfswcbb,"" + iceil(bandnb),"freq_fsw");
                    double freq_throw_cbb = dlookup(tabfswcbb,"" + iceil(bandnb),"freq_throw_" + i);
                    if(fsw_cbb_freq == stabfreq && freq_throw_cbb == freq_throw[i]) {
                        int n_cbb = n;
                        if(bandnb < 6.0) {
                            //only 15 min
                            n_cbb = n / 2;
                        }
                        Proc_stability_freqswitch_COP_CBB(band,stabfreq,freq_throw[i],n_cbb,hrs_mode,integ_time,backend);
                    }
                }
                //
            }
            //
            if(stab == "dbs") {
                n = 450;
                //     
                Init_MSA_HBB_fm(band,"CLOSE",stabfreq,"ON");
                LO_tuning_block_fm(band,stabfreq);
                WBS_calib_fm(band);
                WBS_tune_proc_fm(band);
                HRS_tune_block_fm(band);
                // 
                Proc_stability_dbs(band,n,hrs_mode,integ_time,backend,shutter,chopmode,chop_phase);
            }
            //
        }
    }
    //Back to slow HK readout
    HKrate_block_ops(0.25);
    //end of obsid for LCU switch on 
    StopMode_block_ops();
}

//General script to clear error flags and set to nominal, block
block LCU_enable_FreqTMY_check_block_fm HIFI 3669 {
}{
    //
    //Start_block();
    //switch to standby
    Hifi_HIFI_HL_Standby($BBID);
    {double,string}[] result = ConfigurationReader("name_delays",["stdby_delay"],"0",0.0);
    int stdby_delay = iround(result[0]{0});
    delay(stdby_delay);
    //Clear error flags
    Hifi_HIFI_Conf_LCU_internal($BBID,16383,"RESET","RESET",256);
    //sets bandmask to 3FFF: all bands
    //LSU_delta_f: sets to 256 = 88mV
    //Switch back to nominal
    Hifi_HIFI_HL_Normal($BBID);
    int set_to_nominal_delay = stdby_delay;
    delay(set_to_nominal_delay);
    //
}

// Diplexer scan, very fast, procedure
// Uses the fast OBS TC
procedure Diplexer_scan_proc {
    string band = "3a" in ["0","3a","3b","4a","4b","6a","6b","7a","7b"]; // HIFI band
    double diplexer_current_min_h = -2.24; //starting diplexer current H
    double diplexer_current_min_v = -2.24; //starting diplexer current V
    double diplexer_current_step = 2.24; //Common diplexer current step
    int n_steps = 100; //number of steps
    double stepTime = 0.1; //Step time in seconds: GRANULARITY IS 0.1sec!!!!
    double lo_freq = 807.0; //LO frequency
}{
    //
    //In case of band 6 or 7, use special biases
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v","bias_max_h","bias_max_v"],band,lo_freq);
        //First go to 4mV
        Mixerbias_block_fm(result[2]{0},result[3]{0});
        //Then to 3mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //
    //Fetch diplexer settings
    double[] result_dip = Get_Diplexer_setting(band,lo_freq);
    double diplex_H = result_dip[0];
    double diplex_V = result_dip[1];
    //Perform scan
    Scan_diplexer_block_fm(band,diplexer_current_min_h,diplexer_current_min_h,diplexer_current_step,n_steps,stepTime);
    //
    //Get back to optimal settings
    Set_Diplexer_current_block_fm(diplex_H,diplex_V);
    //
    //In case of band 6 or 7,go back to nominal values
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        //First go to 4mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
        //Then to nominal
        result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //
}

{int,double,double,double,double,double} obs HifiSScanModeDBS {
    string modeName = "freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - DBS slowChop",{data_time,0,0,n_switch_on,0,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,int,int,int,bool,int,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = SScanDBS_pre_timing(band,lo_freq,lo_freq_up,redundancy,effResolution,hr1,hr2,wb1,wb2,data_time,n_switch_on,n_freq_point,n_cycles,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    int n_total = groupnumber * n_cycles;
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = DBS_telescope(naifid,onPosition,band,reffreq,"",pre_timing{0},n_total);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},double,double,double} post_timing = SScanDBS_post_timing(pre_timing{0},telescopetimes,n_freq_point,groupnumber,n_cycles,false);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,reffreq,"",post_timing{1},n_total);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    // normal pre_timing values
    int n_loadinterval = post_timing{1}{7};
    int n_bchop = post_timing{1}{8};
    int shiftlength = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    double avnumchop = post_timing{2};
    // efficiency parameters
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        SScanDBS_commanding(band,reffreq,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,n_cycles,n_total,n_bchop,n_switch_on,n_loadinterval,startobs,telescopetimes,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SScanDBS_deadtimes(band,reffreq,hr1,hr2,wb1,wb2,n_freq_point,data_time,n_bchop,n_switch_on,n_cycles,avnumchop,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanDBS_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,continuumDetection,n_cycles,tscan,tact);
    // Evaluate performance
    SScanDBS_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_total,groupnumber * n_freq_point,avnumchop,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the DBS raster mode
procedure JupiterFastDBSRaster_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 10 in [4,80]; // data dump interval
    int n_int = 20; // number chop cycles to integrate in ICU before transfer
    int n_seq = 1; // number of data transfer cycles per pointing
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF cycles 
    int n_pointsperscan = 1; // Number of points measured before moving to the second pointing phase
    int n_loadinterval = 10; // number of nods before a load measurement
    int n_load = 0; // additional load measurements in one pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,10,0,10,20,21,0,0,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    bool iscross = false; // Whether we use a cross instead of a raster
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Fixed timings in the fast-chop mode
    int load_datatime = GetStdLoadReadout(band,lo_freq);
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time / 2);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,true);
    int readoutdead = FastChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // There is no nod counter in the return values - count this by hand
    int inod = 0;
    // Do I have to make loads in short nods and subsequent holds?
    if(iscross) {
        bool holdforload = n_pointsperscan > 1;
    } else {
        holdforload = n_pointsperscan == 1 && n_loadinterval > n_cycles;
    }
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    int[] choppars = [2 * n_int,0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"jupiter");
            }
            delay(tinitslew - (time() - startobs) - hkduration - loadlength);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            runintostate = false;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            // The use of n_load differs by 1 from the other observing modes here
            for(int i1 = 1 .. n_load - 1) {
                HIFIFastChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle - no load
            HIFIFastChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            // n_pointsperscan=1, n_loadinterval > n_cycles
            if(state[3] % 2 == 1) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
        }
        // Second pointing phase
        if(state[0] == 7) {
            // second nod position
            choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            for(int i2 = 1 .. n_load - 1) {
                HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                choppars = HIFIConfigureFastChopIntegration(data_time,n_int,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle 
            HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            if(state[3] % 2 == 0) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
        }
        // Load nod
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            runintostate = false;
        }
        // Hold
        if(state[0] == 6) {
            // finished shift of instrument operations relative to pointing command
            runintostate = false;
        }
        // Final load
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

/////////////////////////////////////////////////////////////////////////////
// procedure needed for LO tuning
/////////////////////////////////////////////////////////////////////////////
//General LO configuration command
procedure HIFI_Configure_LCU_proc_aot {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978.2; //LO frequency
    int freq_nx = 0; // HL_freq_nx
    int lsu_main = 0; // HL_LSU_main
    int lsu_offset = 0; // HL_LSU_offset
    int d2_step = 1; // HL_D2_step
    double plevel_v = 0.0;
    double m1_v = 9.0;
    double m2_v = -2.0;
    double m3_v = 0.0;
    double gate1_v = -2.5;
    double gate2_v = -2.5;
    double drain1_v = 2.8;
    string curlim1_v = "1.4";
    double drain2_v = 2.6;
    string curlim2_v = "1.4";
    int macro_checksum = 0; // HL_macro_checksum
    int config_lo_delay = 6;
}{
    //Check that Vd2 is within the blue limits
    drain2_v = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v);
    //
    //
    //Execute configuration
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_safe_LCU_ch1a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_safe_LCU_ch1b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_safe_LCU_ch2a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_safe_LCU_ch2b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_safe_LCU_ch3a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_safe_LCU_ch4a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_safe_LCU_ch4b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
    delay(config_lo_delay);
    //
    //Read TM pages and clear error flags
    LCU_Read_TM_pages_proc_aot();
}

//Generic procedure to launch engineering scan applied to chopper rotation, procedure
procedure Engineering_scan_for_chopper_rotation_COP {
    double targetAngle = 0.0; //Target chopper voltage
    int milliSecSample = 3; // interval between samples
    int samplesBefore = 30 in [0,50]; // HIF_N_samples_1
    int samplesAfter = 1000 in [0,1000]; // HIF_N_samples_2
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    //
    targetAngle = Check_Chopper_Prime_Redundant_COP(targetAngle,prime_or_redundant);
    if(prime_or_redundant == "Prime") {
        Hifi_HIFI_P_Chopper_scan_fast(milliSecSample,targetAngle,samplesBefore,samplesAfter);
    } else {
        Hifi_HIFI_R_Chopper_scan_fast(milliSecSample,targetAngle,samplesBefore,samplesAfter);
    }
    //
    // delay calculation
    int nb_HK = 1;
    //For this TC, the 2 last HK fields are blanked out
    int millisecondsUsed = 1000 + 10 + milliSecSample * nb_HK * (samplesBefore + samplesAfter);
    delay(iceil(0.0010 * double(millisecondsUsed)));
    //
}

// HRS partial configuration SPECIFIC TO AOT CUS, block
// Configures the LO and attenuators
block HRS_config_att_lo_block_aot HIFI 6624 {
    string band = "4a"; // HIFI band
    string[] hrs_mode = ["mr","mr"]; //HRS resolution code
    double[] hrsH_LO = [4.5,5.5,6.5,7.5]; //IF position of HRS-H sub-bands
    double[] hrsV_LO = [4.5,5.5,6.5,7.5]; //IF position of HRS-V sub-bands
}{
    // Fetch HRS configuration parameters
    //===================================
    //H-polar
    string hrs_filename_h = "name_confighrs_" + hrs_mode[0];
    {double,string}[] result = ConfigurationReader(hrs_filename_h,["hrh_switch","hrh_1u_att","hrh_1l_att","hrh_2u_att","hrh_2l_att","hrh_3u_att","hrh_3l_att","hrh_4u_att","hrh_4l_att","hrh_down_ol5","hrh_down_ol6","hrh_down_ol7"],band,0.0);
    string hrs_polarization_h = result[0]{1};
    double hrsH_ATT_U1 = result[1]{0};
    double hrsH_ATT_L1 = result[2]{0};
    double hrsH_ATT_U2 = result[3]{0};
    double hrsH_ATT_L2 = result[4]{0};
    double hrsH_ATT_U3 = result[5]{0};
    double hrsH_ATT_L3 = result[6]{0};
    double hrsH_ATT_U4 = result[7]{0};
    double hrsH_ATT_L4 = result[8]{0};
    double[] hrsH_LO_total = [hrsH_LO[0],hrsH_LO[1],hrsH_LO[2],hrsH_LO[3],result[9]{0},result[10]{0},result[11]{0}];
    //V-polar
    string hrs_filename_v = "name_confighrs_" + hrs_mode[1];
    result = ConfigurationReader(hrs_filename_v,["hrv_switch","hrv_1u_att","hrv_1l_att","hrv_2u_att","hrv_2l_att","hrv_3u_att","hrv_3l_att","hrv_4u_att","hrv_4l_att","hrv_down_ol5","hrv_down_ol6","hrv_down_ol7"],band,0.0);
    string hrs_polarization_v = result[0]{1};
    double hrsV_ATT_U1 = result[1]{0};
    double hrsV_ATT_L1 = result[2]{0};
    double hrsV_ATT_U2 = result[3]{0};
    double hrsV_ATT_L2 = result[4]{0};
    double hrsV_ATT_U3 = result[5]{0};
    double hrsV_ATT_L3 = result[6]{0};
    double hrsV_ATT_U4 = result[7]{0};
    double hrsV_ATT_L4 = result[8]{0};
    double[] hrsV_LO_total = [hrsV_LO[0],hrsV_LO[1],hrsV_LO[2],hrsV_LO[3],result[9]{0},result[10]{0},result[11]{0}];
    //
    result = ConfigurationReader("name_delays",["hrs_config_delay"],band,0.0);
    int hrs_config_delay = iround(result[0]{0});
    //
    //Convert IF frequencies into A and M parameters
    int[] a_m_parameter = ComputeA_M_parameters(hrs_mode,hrsH_LO_total[0],hrsH_LO_total[1],hrsH_LO_total[2],hrsH_LO_total[3],hrsH_LO_total[4],hrsH_LO_total[5],hrsH_LO_total[6],hrsV_LO_total[0],hrsV_LO_total[1],hrsV_LO_total[2],hrsV_LO_total[3],hrsV_LO_total[4],hrsV_LO_total[5],hrsV_LO_total[6]);
    //H-polar
    int hrsH_LO1_M = a_m_parameter[1];
    int hrsH_LO1_A = a_m_parameter[0];
    int hrsH_LO2_M = a_m_parameter[3];
    int hrsH_LO2_A = a_m_parameter[2];
    int hrsH_LO3_M = a_m_parameter[5];
    int hrsH_LO3_A = a_m_parameter[4];
    int hrsH_LO4_M = a_m_parameter[7];
    int hrsH_LO4_A = a_m_parameter[6];
    int hrsH_LO5_M = a_m_parameter[9];
    int hrsH_LO5_A = a_m_parameter[8];
    int hrsH_LO6_M = a_m_parameter[11];
    int hrsH_LO6_A = a_m_parameter[10];
    int hrsH_LO7_M = a_m_parameter[12];
    Hifi_HIFI_Config_HRS_H_att_lo($BBID,hrs_polarization_h,hrsH_ATT_U1,hrsH_ATT_L1,hrsH_ATT_U2,hrsH_ATT_L2,hrsH_ATT_U3,hrsH_ATT_L3,hrsH_ATT_U4,hrsH_ATT_L4,hrsH_LO1_M,hrsH_LO1_A,hrsH_LO2_M,hrsH_LO2_A,hrsH_LO3_M,hrsH_LO3_A,hrsH_LO4_M,hrsH_LO4_A,hrsH_LO5_M,hrsH_LO5_A,hrsH_LO6_M,hrsH_LO6_A,hrsH_LO7_M);
    // 
    //delay(hrs_config_delay);
    //V-polar
    int hrsV_LO1_M = a_m_parameter[14];
    int hrsV_LO1_A = a_m_parameter[13];
    int hrsV_LO2_M = a_m_parameter[16];
    int hrsV_LO2_A = a_m_parameter[15];
    int hrsV_LO3_M = a_m_parameter[18];
    int hrsV_LO3_A = a_m_parameter[17];
    int hrsV_LO4_M = a_m_parameter[20];
    int hrsV_LO4_A = a_m_parameter[19];
    int hrsV_LO5_M = a_m_parameter[22];
    int hrsV_LO5_A = a_m_parameter[21];
    int hrsV_LO6_M = a_m_parameter[24];
    int hrsV_LO6_A = a_m_parameter[23];
    int hrsV_LO7_M = a_m_parameter[25];
    Hifi_HIFI_Config_HRS_V_att_lo($BBID,hrs_polarization_v,hrsV_ATT_U1,hrsV_ATT_L1,hrsV_ATT_U2,hrsV_ATT_L2,hrsV_ATT_U3,hrsV_ATT_L3,hrsV_ATT_U4,hrsV_ATT_L4,hrsV_LO1_M,hrsV_LO1_A,hrsV_LO2_M,hrsV_LO2_A,hrsV_LO3_M,hrsV_LO3_A,hrsV_LO4_M,hrsV_LO4_A,hrsV_LO5_M,hrsV_LO5_A,hrsV_LO6_M,hrsV_LO6_A,hrsV_LO7_M);
    // 
    delay(hrs_config_delay);
}

//Retune HIFI for frequency switch - keep magnet and backends
procedure HIFITuneFreqFsw {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq_1 = 978200.0; //LO frequency for FSW1 phase
    double lo_freq_2 = 978300.0; //LO frequency for FSW2 phase
    bool newsetting = true; // whether LSU/LOU parameters are new
    string target_name = "sscan_normal"; // Name of target level
}{
    //LO power tuning: could use either H or V polar
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq_1);
    double x = result[0]{0};
    string tuningbackend = "H";
    if(iround(x) == 2) {
        tuningbackend = "V";
    } else {
        tuningbackend = "H";
    }
    // All tuning for first frequency, and store in FSW1 register
    double lo_freq_setting = 0.5 * (lo_freq_1 / 1000.0 + lo_freq_2 / 1000.0);
    LO_tuning_block_aot(band,lo_freq_1 / 1000.0,lo_freq_setting,tuningbackend,newsetting,newsetting,true);
    //
    //Spectrometer attenuator tuning - on the sky or cold load
    if(target_name != "") {
        WBS_attenuators_block(band,lo_freq_1 / 1000.0,target_name,true);
    }
    //
    // Second frequency setup, and stored in FSW2 register
    LO_tuning_block_aot(band,lo_freq_2 / 1000.0,lo_freq_setting,tuningbackend,false,newsetting,true);
    //
}

// Chop between internal cold and external hot loads, block
// We take 1 spectrum per phase.
block Stability_intcold_exthot_fm HIFI 3434 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integration pairs 
    int integ_time = 4; //Total (co-added) integration time of ONE SINGLE phase in sec.
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "slowchop" in ["slowchop","fastchop"]; //Whether to use slowchop or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    Start_block();
    //Get chopper settings
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_M3","chop_cold"],band,0.0);
    double chop_middle = result[0]{0};
    double chop_cold = result[1]{0};
    //
    //We implement a special slow-chop spectroscopy between
    //internal cold and external hot
    if(chopmode == "slowchop") {
        Slow_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_middle,chop_cold);
    } else {
        Fast_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_middle,chop_cold,chop_phase);
    }
}

//Procedure checking whether commanded voltage is in the acceptable range
double procedure Check_Chopper_Range_COP {
    double chopper_angle = 0.0; //prime or redundant chopper voltage
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red 
}{
    //Check prime or redundant status
    {double,string}[] result_d = ConfigurationReader("name_chopper",["prime_endstop_min","prime_endstop_max","red_endstop_min","red_endstop_max"],"0",0.0);
    double chop = chopper_angle;
    double prime_endstop_min = result_d[0]{0};
    double prime_endstop_max = result_d[1]{0};
    double red_endstop_min = result_d[2]{0};
    double red_endstop_max = result_d[3]{0};
    //
    //Checks the chopper angle is within the ranges
    if(prime_or_redundant == "Prime") {
        if(chop > prime_endstop_max || chop < prime_endstop_min) {
            error("The chopper voltage (requested is " + chop + " V) in " + result_d[0]{1} + " mode has to be between " + prime_endstop_min + " and " + prime_endstop_max + " V.");
        }
    }
    if(prime_or_redundant == "Red") {
        if(chop > red_endstop_max || chop < red_endstop_min) {
            error("The chopper voltage (requested is " + chop + " V) in " + result_d[0]{1} + " mode has to be between " + red_endstop_min + " and " + red_endstop_max + " V.");
        }
    }

    return chop;
}

// Integrate only on internal cold, block
// We take 1 spectrum per phase.
block Stability_intcold_fm HIFI 3426 {
    string band = "1a"; // HIFI band
    int n = 100; //The number of integrations
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    string obsmode = "fastchop" in ["fastchop","tp"]; //tp or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    Start_block();
    Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_cold_ang");
    //Look at CBB
    //Get chopper settings
    {double,string}[] result = ConfigurationReader("name_confilfpu",["chop_cold"],band,0.0);
    double chop_cold = result[0]{0};
    //Do a long integration
    //	- for B1-5, use 2 sec. with wbs or hrs only, thus tp is OK
    //  - for B6: use 1 sec. with reduced wbs (wbsFast), thus tp is OK
    //We implement a special spectroscopy configuration with fixed values
    if(obsmode == "tp") {
        Total_power_spectro_for_Stability_proc_fm(band,n,integ_time,backend,hrs_mode);
    }
    if(obsmode == "fastchop") {
        Fast_chop_spectro_for_Stability_proc_fm(band,n,integ_time * 2,backend,hrs_mode,chop_cold,chop_cold,chop_phase);
    }
}

// Stability test, procedure
// Measurement of internal cold only
procedure Proc_stability_intcold {
    string band = "1a"; // HIFI band
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total integration time in sec. to be set at end of test
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string obsmode = "fastchop" in ["fastchop","tp"]; //tp or fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    //
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_cold_ang");
    //Look at CBB
    //
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        //Configure and tune backends
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration: done later
    //Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);	//2 sec. integration
    //
    Stability_intcold_fm(band,n,integ_time,backend,hrs_mode,obsmode,chop_phase);
    //Configure spectrometers integration back to default
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the DBS raster mode
procedure DBSRaster_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size
    int n_seq = 1; // Number of continuous chop cycles
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF cycles 
    int n_pointsperscan = 1; // Number of points measured before moving to the second pointing phase
    int n_loadinterval = 10; // number of nods before a load measurement
    int n_load = 0; // additional load measurements in one pointing phase
    bool final_load = false; // Need for final load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,10,0,10,20,21,0,0,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
    bool iscross = false; // Whether we use a cross instead of a raster
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get all values from the telescope section  
    int tinitslew = telescopetimes[1];
    // Initial slew time
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // Count phases by hand to allow simultaneous usage by Raster and Cross
    int iphase = 0;
    // There is no nod counter in the return values - count this by hand
    int inod = 0;
    // Do I have to make loads in short nods and subsequent holds?
    if(iscross) {
        bool holdforload = n_pointsperscan > 1;
    } else {
        holdforload = n_pointsperscan == 1 && n_loadinterval > n_cycles;
    }
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    bool runintostate = false;
    while(state[0] >= 0) {
        if(runintostate) {
            state = next_state_no_check();
        } else {
            state = next_state();
        }
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
            iphase = iphase + 1;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            // Loop for load cycles
            // The use of n_load differs by 1 from the other observing modes here
            for(int i1 = 1 .. n_load - 1) {
                HIFISlowChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle 
            HIFISlowChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            // n_pointsperscan=1, n_loadinterval > n_cycles
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == 1) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
            // Update phase counter
            iphase = iphase + 1;
        }
        // Second pointing phase
        if(state[0] == 7) {
            // second nod position
            HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            for(int i2 = 1 .. n_load - 1) {
                HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
                // Perform load calibration
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                HIFIConfigureSlowChopIntegration(data_time,n_seq,band,lo_freq,backendreadoutparms);
            }
            // Last cycle 
            HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
            // Load measurement if required - time included in pointing
            if(n_load > 0) {
                delay(readoutdead);
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            // Final point before nod
            // Special treatment for all cases where load has to be replaced by hold:
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == 1) {
                inod = inod + 1;
                if(holdforload && inod % n_loadinterval == 0 && n_load == 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    runintostate = true;
                }
            } else {
                // keep shift if we come from a holdforload nod, otherwise reset
                if(!holdforload) {
                    runintostate = false;
                }
            }
            // Update phase counter
            iphase = iphase + 1;
        }
        // Load nod
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
        }
        // Hold
        if(state[0] == 6) {
            // finished shift of instrument operations relative to pointing command
            runintostate = false;
        }
        // Final load
        if(state[0] == 5) {
            delay(readoutdead);
            if(final_load) {
                // Perform final load measurement 
                LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

/////////////////////////////////////////////////////////////////
// Procedure to compute total dead times for the mode
// 
{double,double,double} procedure FastDBS_deadtimes {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // data dump interval
    int n_int = 20; // number of integrations in one data dump interval
    int n_data = 3; // number of subsequent readouts
    int n_load = 0; // number of integrations in one pointing phase -1
    double tdead = 10.0; // Dead time from telescope
}{
    //////////////////////////////////////////////////////////////////////
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Compute parameters for the instrument timing
    {double,double} tinst = GetInstDeadFastChop(data_time,n_int,n_data,band,lo_freq,backendreadoutparms);
    // dead time
    double tdeadint = double(data_time * n_data) - tinst{0};
    // subtract dead times in switches
    // only half of them are subtracted due to ABAB scheme
    tdeadint = tdeadint - double(n_int * n_data) * tinst{1};
    // Total dead time per cycle
    double tdead_tot = tdead + double(2 * (n_load + 1)) * tdeadint;
    // Integration time
    double tphaseint = tinst{0} / double(2 * n_int * n_data);

    return {tdead_tot,tphaseint,tinst{1}};
}

// Initialisation, block with IF1 set OFF
block Init_noIF1_fm HIFI 3209 {
    string band = "1a"; // HIFI band
    string mixer_polarization = "B" in ["H","V","B"]; //Polarization: H, V, or both (B) 
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,0.0);
    int band_nb = iround(result_d[0]{0});
    //
    double volt_H_FIF_1 = 0.075;
    double curr_H_FIF_1 = 0.5;
    double volt_H_FIF_2 = 0.075;
    double curr_H_FIF_2 = 0.5;
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // Check whether H-polar is requested
    if(mixer_polarization == "V") {
        volt_H_SIF_1 = 0.075;
        curr_H_SIF_1 = 0.5;
        volt_H_SIF_2 = 0.075;
        curr_H_SIF_2 = 0.5;
        volt_H_SIF_3 = 0.075;
        curr_H_SIF_3 = 0.5;
    }
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,0.0);
    //
    double volt_V_FIF_1 = 0.075;
    double curr_V_FIF_1 = 0.5;
    double volt_V_FIF_2 = 0.075;
    double curr_V_FIF_2 = 0.5;
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    // Check whether H-polar is requested
    if(mixer_polarization == "H") {
        volt_V_SIF_1 = 0.075;
        curr_V_SIF_1 = 0.5;
        volt_V_SIF_2 = 0.075;
        curr_V_SIF_2 = 0.5;
        volt_V_SIF_3 = 0.075;
        curr_V_SIF_3 = 0.5;
    }
    //
    string chop_sine_s = "ON";
    string chop_loop = "CLOSE";
    //Chopper is not used anyway
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,0.0);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    //Junctions do not need to be biased, nor should diplexers be moved
    double bias_H = 0.0;
    double magnetcurrent_H = 0.0;
    double bias_V = 0.0;
    double magnetcurrent_V = 0.0;
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double chopper = 0.0;
    //
    //
    chopper = Check_Chopper_Prime_Redundant(chopper);
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,0.0);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //
}

//HIFI-COP-1.2-LO_FT
procedure LO_FT_COP_proc_sft {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_comment("Start of HIFI LO Functional Test for band " + band);
    mois_comment("Please check that instrument was switched on with the " + prime_or_redundant + " unit");
    mois_tmcheck("Check content of AND LCU_temperatures_with HIFI expert.");
    //General parameters in use
    string multiplier = "ALL";
    int operation_delay = 0;
    //
    double[] cresult_d = CalibrationReader("name_keyfreq",["keyfreq"],band,0.0);
    double lo_freq = cresult_d[0];
    //applies to cold LO
    //
    mois_step("Init MSA");
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    Init_MSA_ops(band,"CLOSE",lo_freq,result[0]{0},"ON",prime_or_redundant);
    //
    //First switch off the band.
    LCU_switch_off_block_fm();
    mois_tmcheck("Check that parameter HL_Channel_S is OFF");
    //
    mois_step("Measure LCU IV curve");
    Measure_LCU_IV_proc_fm(band,multiplier,operation_delay);
    //
    //Switch on with safe Vd2
    mois_step("Switch on LO band");
    LCU_switchon_proc_sft(band);
    mois_tmcheck("Check that parameter HL_MODE_S is normal");
    mois_tmcheck("Check that parameter HL_Channel_S is " + band);
    //
    mois_step("LO SFT");
    //This will switch on the chain again
    LO_SFT_proc_sft(band,prime_or_redundant);
    //
    mois_tmcheck("Check whether parameter HL_error_word_S has been FAULT at any time of the procedure. Communicate occurences to HIFI expert.");
    mois_tmcheck("Check content of AND LCU_status2 and LCU_" + band + " with HIFI expert.");
}

////////////////////////////////////
// Routines to provide initial guesses for sequence parameters
////////////////////////////////////
// Frequency switch observing mode
//
{string,double,double}[] procedure HifiPointProcFSwitchSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int n_switch_off = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF calibration cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    {double,double,double,double} phaselengths = FSwitchPhaseLengths(band,lo_freq,effResolution,oneGHzReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_switch_on_guess = imax(iceil(phaselengths{0} / (2.0 * double(data_time_guess))),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,2 * n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    new_data_time = MatchMinPointing(data_time_off_guess,data_time_off_range,2 * n_switch_off_guess);
    data_time_off_guess = new_data_time{0};
    data_time_off_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)}];

    return retvalues;
}

//FSW Integration on Internal hot, block
block Hot_spectra_FSW_fm HIFI 3233 {
    string band = "1a";
    int integ_time = 8; //Total integration time in sec.: at least 2sec !
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //Rotate chopper: assume we come from M3
    Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_hot_ang");
    //
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"fsw",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    Hifi_HIFI_Spectr_freq_switch($BBID);
    Apply_Slow_Chop_delay(integ_time,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

// Get main beam size for message 
double procedure GetMainBeamSize {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] fwhm = CalibrationReader("beam",["resolution"],band,lo_freq);

    return fwhm[0];
}

//Chopper health check test#3 during CL, mode
mode HifiManCmd_Chopper_closed_loop_parameter_check_ops {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    string prime_or_redundant = "Prime" in ["Prime","Red"]; //Prime or Red
}{
    mois_tmcheck("This should be the very first test performed after transition between open loop and closed loop contexts");
    mois_tmcheck("The instrument should be in Standby I mode in CL context for this test");
    //It is done after chopper has been switched on in closed loop
    //
    mois_comment("Performing part three of HIFI internal chopper health check");
    StartMode_block_ops();
    //
    //Get chopper ON in closed-loop with voltage at rest position
    string chop_startup_prime_red = "chop_startup_cold_prime";
    if(prime_or_redundant == "Red") {
        chop_startup_prime_red = "chop_startup_cold_red";
    }
    {double,string}[] result = ConfigurationReader("name_chopper",[chop_startup_prime_red],"0",0.0);
    //Remove loop closure to be in line with procedure and re-generate MOIS
    //Loop closure is done via context transition procedure NCXT/RCXT
    //Init_MSA_ops("0","CLOSE",0.0,result[0]{0},"ON",prime_or_redundant);
    mois_tmcheck("Check that parameter HF_DPR_CHLOOP_S is set to CLOSE");
    mois_tmcheck("Check that parameter HF_DPR_CH_ROT is set to " + result[0]{0} + " V");
    Chopper_closed_loop_parameter_check_block_ops(prime_or_redundant);
    StopMode_block_ops();
    mois_spacon("Complete success of this integrity check needs off-line analysis. Please write down the OBS_ID corresponding to this mode and communicate it to the HIFI ICC");
}

{int,double,double,double,double,double} obs HifiMappingModeFSwitchOTF {
    string modeName = "fs-raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 1 in [1,1800]; // Supersamplingfactor
    int n_switch_off = 3 in [1,3600]; // Number of data dumps for the OFF integration time
    int n_linesperscan = 1 in [1,32]; // Number of lines between two OFFs
    int n_cycles = 1 in [1,1200]; // Number of map coverages
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Mapping - OTF Map Frequency Switch Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,n_linesperscan,0,0,n_cycles,load_interval});
    // Auxiliary routine for API parameter correction
    {double,double,int} mapused = ValidMapSize(band,lo_freq,lineDistance,nlines,stepsize,npoints,2 * data_time * n_switch_on);
    double line_used = mapused{0};
    double scanvelocity = mapused{1};
    int npoints_used = mapused{2};
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int} pre_timing = OTFFSwitch_pre_timing(nlines,npoints_used,band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_linesperscan,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,double,double,int,int,double,double,int,int,int,int,int} tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,pre_timing);
    // Dummy call to spacecraft command
    int[] telescopetimes = line_scan_with_off_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int},double,double} post_timing = OTFmap_post_timing(pre_timing,telescopetimes,data_time,n_linesperscan,n_cycles,load_interval);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = OTFmap_telescope(naifid,onPosition,lineDistance,nlines,line_used,refPosition,scanvelocity,band,lo_freq,n_linesperscan,n_cycles,post_timing{1});
    // Call telescope command
    telescopetimes = line_scan_with_off_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23});
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int n_pp = post_timing{1}{0};
    int n_scans = post_timing{1}{1};
    int off_inttime = post_timing{1}{2};
    int loadlength = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{5};
    double tscan = post_timing{2};
    double tdead = post_timing{3};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        OTFFSwitch_commanding(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,npoints_used * n_switch_on,n_switch_off,nlines * n_cycles,n_linesperscan,n_loadinterval,startobs,telescopetimes,loadlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = OTFDoubleChop_deadtimes("fs",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_linesperscan,n_pp,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = OTFFSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,nlines,data_time,n_switch_on,n_linesperscan,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    OTFDoubleChop_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints_used,n_switch_on,n_switch_off,n_scans,n_cycles,true,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

////////////////////////////////////
// Auxiliary  functions
// IsContained functions
bool procedure StringIsContained {
    string x = " "; // search string
    string[] lot = [""]; // array to be searched
}{
    int nlen = length(lot);
    bool found = false;
    for(int i = 0 .. nlen - 1) {
        if(x == lot[i]) {
            found = true;
        }
    }

    return found;
}

// Switch on LO band: assumes HIFI is prime and LO is in nominal mode
// This is wrapped into an engineeering obs in MTL
// During the stabilization phase a normal load-chop-noref observation
// is performed
obs HifiEngSwitchonLO {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    bool robust = true; // whether the subsequent AOR is chopped+spectroscopic
}{
    // First part - determine timing and telescope parameters
    // Fixed parameters
    int data_time = 4;
    // Data readout period
    {double,double} eff_resolution = {1.1,1.1};
    // Native WBS resolution as goal resolution
    // Get reference frequency
    string keyfreqname = "keyfreq";
    //this is for cold LO operations
    // "keyfreq" for cold LO operations
    // "keyfreq_dummy"  for dummy LO operations
    // "midfreq" old approach
    double[] result_d = CalibrationReader("name_keyfreq",[keyfreqname],band,0.0);
    double lo_freq = result_d[0] * 1000.0;
    // Backend settings
    // standard routine from spectral scans
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,2,true,true,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    // Call specific pre_timing computer
    {int,int,int,int,int,int} pre_timing = SwitchOnLoadChop_pre_timing(band,lo_freq,eff_resolution,hr1,hr2,wb1,wb2,data_time,robust);
    // get parameters for fine pointing
    int totaltime = pre_timing{0};
    // total duration for check
    int on_pointing = pre_timing{1};
    // Pointing time
    int initlength = pre_timing{2};
    // Initial setup time
    int dangling = pre_timing{3};
    // Final load measurement
    // telescope command
    int[] ts = no_pointing(true,initlength,dangling,on_pointing);
}{
    // Second part - instrument commanding
    // get parameters for instrument
    int n_cycles1 = pre_timing{4};
    int n_cycles = pre_timing{5};
    // Backend settings
    // Create a composite readout structure
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hr1{0},hr1{1},hr1{3}},{hr2{0},hr2{1},hr2{3}},wb1,wb2};
    // additional fixed parameters like in standard observing modes
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] rates = dataparms{1};
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    //////////////////
    // Instrument commanding
    sync();
    int startobs = time();
    // use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
            // Actual switch-on
            // The switch will always be done at the same frequency
            LCU_switchon_proc_aot(band,lo_freq / 1000.0);
            // Initial setup and LO tuning
            Init_Mixing_proc_aot(band,lo_freq / 1000.0);
            //Deflux will do be done for bands 1 to 4
            Deflux_SingleBand_proc_aot(band,lo_freq / 1000.0);
            // Standard backend tuning
            string target_name = "normal";
            // Name of target level
            if(wb1{0} || wb2{0}) {
                WBS_attenuators_block(band,lo_freq / 1000.0,target_name,false);
            }
            if(hr1{0} || hr2{0}) {
                HRS_tune_block_aot(band);
            }
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
        }
        if(state[0] == 3) {
            // ON integration - long hot-cold measurement
            if(n_cycles1 > 0) {
                HIFI_Calibrate_hot_cold(band,lo_freq,data_time,2 * n_cycles1,backendreadoutparms,false);
                HIFITuneFreq(band,lo_freq,false,"");
            }
            HIFI_Calibrate_hot_cold(band,lo_freq,data_time,2 * n_cycles,backendreadoutparms,false);
        }
        if(state[0] == 5) {
            delay(readoutdead);
            // Perform final load measurement 
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            HIFICloseObs();
        }
    }
    // Finalize observations
    // consistency check
    int timeTaken = time() - startobs;
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    // Noise estimates could be easily added, but are not done here
    // in the current implementation
}

//Set LCU1a back to standby status, procedure
procedure LCU1a_standby_proc_fm {
    string band = "1a"; // HIFI band
    double lo_freq = 500.0 in [488.0,552.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_standby_proc_fm  instead");
}

{string,double,double}[] procedure HifiSScanModeFastDBSSequencerInit {
    string modeName = "freq";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time / 2);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hr1{0},hr1{1},hr1{3}},{hr2{0},hr2{1},hr2{3}},wb1,wb2};
    // Get frequency grid characteristic parameters
    {double,int,double} gfref = GetFReference(band,lo_freq,lo_freq_up);
    double reffreq = gfref{0};
    int stdredun = gfref{1};
    double stdstep = gfref{2};
    int increment = stdredun / redundancy;
    // allowed group size
    double nocaliblen = GetFNoCalibLength(band,reffreq);
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    // Now general part of DBS modes
    // Get the drift parameters to compute the drift noise
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {double,double} phaselengths = DBSPhaseLengths(band,reffreq,effResolution,continuumDetection,narrowReference);
    // Compute derived quantities
    // Top down approach here
    int main_phase = iceil(phaselengths{0});
    // Arbitrary selection of data_time
    int data_time_guess = 20;
    // remaining part for n_switch
    int n_switch_on_guess = main_phase / (n_freq_point_guess * data_time_guess) + 1;
    data_time_guess = main_phase / (n_freq_point_guess * n_switch_on_guess);
    // Check with data rate
    {int,double[]} dataparms = DataTaking(backendreadoutparms,8);
    int datalimit = 2 * dataparms{0};
    if(data_time_guess < datalimit) {
        data_time_guess = datalimit;
        n_switch_on_guess = 1;
    }
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // Chop phase length
    double phase_min = min(max(phaselengths{1},0.15),1.5);
    int n_int_on_guess = ifloor(double(data_time_guess) / (2.0 * phase_min));
    int n_int_on_range = -n_int_on_guess / 2;
    if(n_int_on_range == 0) {
        n_int_on_range = 1;
    }
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_int_on",double(n_int_on_guess),double(n_int_on_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)}];

    return retvalues;
}

//Procedure checking whether the requested integration
//time is compliant with the allowed packet/datarate
//in fast chop spectroscopy context
bool procedure Check_Fast_Chop_datarate {
    int n_wbs_start = 1; //Nb of frames
    int r_hrs = 1; //Nb of HRS readout per WBS readout
    int n_wbs_integr = 4; //Number of wbs readout packetized per WBS frame
    int n_hrs_integr = 4; //Number of hrs readout packetized per HRS frame
    int del_hrs = 5; //Delay before starting HRS integration
    int del_wbs = 5; //Delay before starting WBS integration
    int t_acc_wbs = 1005; //Duration of WBS frame 
    int t_acc_hrs = 950; //Duration of HRS frame
    int wbsh_offset1 = 0;
    int wbsh_width1 = 2048;
    int wbsh_offset2 = 2048;
    int wbsh_width2 = 2048;
    int wbsh_offset3 = 4096;
    int wbsh_width3 = 2048;
    int wbsh_offset4 = 6144;
    int wbsh_width4 = 2048;
    int wbsv_offset1 = 0;
    int wbsv_width1 = 2048;
    int wbsv_offset2 = 2048;
    int wbsv_width2 = 2048;
    int wbsv_offset3 = 4096;
    int wbsv_width3 = 2048;
    int wbsv_offset4 = 6144;
    int wbsv_width4 = 2048;
    int hrs_rshift = 0; //HRS bit shift
    int wbs_rshift = 0; //WBS bit shift
    int hrsh_sel = 255; //HRS-H band selection
    int hrsv_sel = 255; //HRS-V band selection
    string wbs_packing = "24_bits_format";
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3
    int n_wbs_1 = 8; //n_wbs_1: number of WBS cycles (should be even)
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    error("Procedure Check_Fast_Chop_datarate is not used anymore.");

    return false;
}

//Peak test data aquisition, block
block Peakup_test_acquire_data_block_fm HIFI 3821 {
    string band = "1" in ["1","2","3","4","5","6","7"]; // HIFI band
    string backend = "hrs" in ["hrs","wbs"]; //Backend in use: hrs or wbs
    int total_time = 2; //Total integration time in sec.
    string peakup_matrix = "centred" in ["centred","offseted","flat"]; //Which brightness distribution to simulate with shutter
    string mixer_polarization = "H" in ["H","V"]; //mixer polarization to be used 
}{
    //Start_block();
    //Get some data for delay computation
    string band_nb = band + "a";
    {double,string}[] result = ConfigurationReader("name_delays",["wbs_transfer_delay"],band_nb,0.0);
    int wbs_packet_transfer_time = iround(result[0]{0});
    //
    //Loop on positions: succesively move shutter and acquire data
    for(int position = 1 .. 9) {
        //Move shutter: this is equivalent to the telescope motion
        ////Peakup_shutter_rotation_proc_fm(band,position,peakup_matrix);
        //THE ABOVE IS NOT AVAILABLE IN IST - WE USE BACKEND ATT. INSTEAD
        Peakup_backend_attenuation_proc_fm(band,position,peakup_matrix,backend,total_time);
        //Acquire data
        if(backend == "hrs") {
            Hifi_HIFI_acquire_peakup_hrs($BBID,mixer_polarization,position);
            delay(total_time + wbs_packet_transfer_time / 1000);
        } else {
            Hifi_HIFI_acquire_peakup_wbs($BBID,mixer_polarization,position);
            delay(total_time + wbs_packet_transfer_time / 1000);
        }
        //Add a short integration to get distribution of IF power independently
        Hifi_HIFI_Spectr_total_power($BBID);
        delay(total_time + wbs_packet_transfer_time / 1000 + 1);
    }
    //
    //Trigger AOCS correction computation (?)
    Hifi_HIFI_correction_AOCS($BBID);
    delay(1);
}

// Initialisation of FPU, block with both MSA in use
// It is for warm context !
block Init_MSA_fm_warm HIFI 3216 {
    string band = "1a"; // HIFI band
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
}{
    Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReaderWarm("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReaderWarm("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReaderWarm("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    //
    //Get biases
    result_d = ConfigurationReaderWarm("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReaderWarm("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReaderWarm("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode","diplexer_current_normal_h","diplexer_current_normal_v"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        //double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_d[2]{0};
        //result_dip[0];
        diplex_V = result_d[3]{0};
        //result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    double chopper = result_d[0]{0};
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReaderWarm("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    Hifi_HIFI_non_periodic_hk_FCU();
}

////////////////////////////////////
// Position switch observing mode
// 
// Combination of four modules implementing the new structure 
//
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiPointProcPositionSwitch {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    bool refSelected = true; // Dummy parameter required by HSPOT
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[36,2012],[36,2012],[36,2012],[36,2012]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,5]; // data dump interval limited by the data rates
    int n_int_on = 3 in [2,1800]; // number of data dumps for integration per phase
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Single Point - Position Switch",{data_time,0,n_int_on,0,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} pre_timing = PositionSwitch_pre_timing(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},double,double} post_timing = PositionSwitch_post_timing(pre_timing,telescopetimes,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,post_timing{1},n_cycles);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},true);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    int loadlength = post_timing{1}{4};
    int n_loadinterval = post_timing{1}{7};
    bool final_load = post_timing{1}{12};
    double tscan = post_timing{2};
    double tdead = post_timing{3};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        PositionSwitch_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,startobs,telescopetimes,n_loadinterval,loadlength,final_load);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    double tdead_tot = PositionSwitch_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = PositionSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,n_cycles,tscan,tdead_tot);
    // Evaluate performance
    PositionSwitch_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,tscan,tdead_tot);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

//////////////////////////////////////////////////////////////////////
// Procedure to display performance parameters of the observing mode
procedure DBS_performance {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {double,double,double,double,double} noisevalues = {1.0,1.0,1.0,1.0,0.0}; // Noise values from noisecomputer
    int totaltime = 200; // Total observing time
    int n_cycles = 1; // Number of nodding cycles
    int n_chop = 1; // number of chop cycles
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double} tact = {10.0,4.9,0.05}; // Field of actual dead and integration times
}{
    double inttimeperphase = tact{1};
    // Actual integration time in ON phase
    // Get performance of ideal instrument for comparison
    {int,double,double,double,double,double} idealvalues = IdealInstrument(band,lo_freq,eff_resolution,totaltime);
    double idealnoise = idealvalues{1} * idealvalues{1};
    double obsnoise = noisevalues{0} * noisevalues{0};
    double efficiency = idealnoise / obsnoise;
    // Compute the actual integration time
    double posinttime = double(n_cycles * 2 * n_chop) * inttimeperphase;
    int instrumenttime = iceil(double(n_cycles) * tscan);
    // Check total integration time
    double timeefficiency = 2.0 * posinttime / double(totaltime);
    // Noise contribution
    double relnoise = noisevalues{4} / (1.0 + noisevalues{4});
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posinttime,timeefficiency,efficiency,relnoise,false);
}

////////////////////////////////////
// Routine to provide initial guesses for sequence parameters
// Frequency switch observing mode
//
{string,double,double}[] procedure HifiPointProcFSwitchNoRefSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_cycles = 2 in [1,3600]; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // inherit from load-chop mode
    {string,double,double}[] retvalues = HifiPointProcLoadChopNoRefSequencerInit(naifid,ra,dec,band,lo_freq,effResolution,oneGHzReference,hrs1,hrs2,wbs1,wbs2,data_time,n_cycles,load_interval,docommands);

    return retvalues;
}

//
// WBS configuration, block
// Both polarizations are treated
block WBS_config_block_fm HIFI 3625 {
    string band = "1a"; // HIFI band
}{
    //Start_block();
    //H-Polarization
    //
    {double,string}[] result_d = ConfigurationReader("name_configwbs",["hwh_laser1_s","hwh_laser2_s","hwh_heater","hwh_latchup_s","hwh_att_band4","hwh_att_band3","hwh_att_band2","hwh_att_band1","hwh_att_in"],band,0.0);
    string hwh_laser1_s = result_d[0]{1};
    string hwh_laser2_s = result_d[1]{1};
    int hwh_heater = iround(result_d[2]{0});
    string hwh_latchup_s = result_d[3]{1};
    int hwh_att_band4 = iround(result_d[4]{0});
    int hwh_att_band3 = iround(result_d[5]{0});
    int hwh_att_band2 = iround(result_d[6]{0});
    int hwh_att_band1 = iround(result_d[7]{0});
    int hwh_att_in = iround(result_d[8]{0});
    //
    result_d = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result_d[0]{0});
    //       
    //Configure WBS-H
    Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
    //
    //delay(wbs_config_delay);	//Wait for configuration to be applied
    //
    //V-Polarization
    //
    result_d = ConfigurationReader("name_configwbs",["hwv_laser1_s","hwv_laser2_s","hwv_heater","hwv_latchup_s","hwv_att_band4","hwv_att_band3","hwv_att_band2","hwv_att_band1","hwv_att_in"],band,0.0);
    string hwv_laser1_s = result_d[0]{1};
    string hwv_laser2_s = result_d[1]{1};
    int hwv_heater = iround(result_d[2]{0});
    string hwv_latchup_s = result_d[3]{1};
    int hwv_att_band4 = iround(result_d[4]{0});
    int hwv_att_band3 = iround(result_d[5]{0});
    int hwv_att_band2 = iround(result_d[6]{0});
    int hwv_att_band1 = iround(result_d[7]{0});
    int hwv_att_in = iround(result_d[8]{0});
    //       
    //Configure WBS-V
    Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
    //
    delay(wbs_config_delay);
    //Wait for configuration to be applied
    //
}

//TM to control heater values of LOU, block
block HL_heater_block_aot HIFI 6615 {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band.
    string context = "nominal" in ["nominal","stby"]; //whether heater applies to stby or nominal context
}{
    double[] cresult = CalibrationReader("name_loheater",["heater_nominal","heater_stby"],band,0.0);
    double hifi_HL_heater = cresult[0];
    if(context == "stby") {
        hifi_HL_heater = cresult[1];
    }
    Hifi_HIFI_HL_heater($BBID,hifi_HL_heater);
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// CUS scripts for ICU operations.
//
// DT - 17-Feb-06
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The modes
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//See fm_testmodes.cus
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// The blocks
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//HIFI HK control, block
block Switch_HK_block_fm HIFI 3905 {
    string hk_FCU = "ON" in ["ON","OFF"]; //Status of FCU HK
    string hk_LCU = "ON" in ["ON","OFF"]; //Status of LCU HK
    string hk_WBSV = "ON" in ["ON","OFF"]; //Status of WBSV HK
    string hk_WBSH = "ON" in ["ON","OFF"]; //Status of WBSH HK
    string hk_HRSV = "ON" in ["ON","OFF"]; //Status of HRSV HK
    string hk_HRSH = "ON" in ["ON","OFF"]; //Status of HRSH HK
}{
    Start_block_no_hk_request();
    //Get applicable HK rate
    {double,string}[] result_d = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    string hk_rate = result_d[0]{1};
    Hifi_HIFI_Housekeeping_on(hk_rate,hk_FCU,hk_LCU,hk_WBSV,hk_WBSH,hk_HRSV,hk_HRSH);
    delay(1);
}

//FSW Integration on Internal cold, block
block Cold_spectra_FSW_fm HIFI 3234 {
    string band = "1a";
    int integ_time = 8; //Total integration time in sec.: at least 2sec !
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //Rotate chopper: assume we come from M3
    Chopper_Rotation_proc_fm(band,"chop_M3_ang","chop_cold_ang");
    //
    //Compute data-rate
    double[] rates = ILT_datarate_proc_fm(band,backend,"fsw",integ_time);
    //Take spectrum
    // set data rates
    non_ess_hk_data_rate(rates[2] / 1024.0);
    data_rate(rates[0] / 1024.0);
    //
    Hifi_HIFI_Spectr_freq_switch($BBID);
    Apply_Slow_Chop_delay(integ_time,band,backend);
    // reset data rates
    non_ess_hk_data_rate(rates[1] / 1024.0);
    data_rate(0.0);
}

//HIFI LO configuration only for M1/M2 investigation in 7b, block
block LCU_config_w_M1M2D2_block_fm HIFI 3924 {
    string band = "7b" in ["7b","7b"]; // HIFI band
    double lo_freq = 1880.0; //LO frequency
    double m1 = -8.0; //M1 multiplier voltage
    double m2 = -8.0; //M2 multiplier voltage
    double drain2_v = 1.5; //Vd2 voltage
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    {double,string}[] result = ConfigurationReader("name_confpolar4lotune",[band],band,lo_freq);
    string mixer_polarization = result[0]{1};
    //
    //Get target mixer current
    result = ConfigurationReader("name_confilmix",["target_mx_c_h","target_mx_c_v"],band,lo_freq);
    double target_current = result[0]{0};
    if(mixer_polarization == "V") {
        target_current = result[1]{0};
    }
    if(mixer_polarization == "B") {
        target_current = 0.5 * (result[1]{0} + result[0]{0});
    }
    //
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcutune_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcutune_b";
    }
    //
    result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = m1;
    //result[1]{0};
    double m2_v = m2;
    //result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    //double drain2_v = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    double step_drain2_v = result[0]{0};
    int nsteps = iround(result[1]{0});
    double step_time = result[2]{0};
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //
    if(band == "7b") {
        Hifi_HIFI_Conf_nom_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v,curlim2,macro_checksum);
        //
        delay(config_lo_delay);
        //
        //Additional read of TM pages
        LCU_Read_TM_pages_proc_fm();
    }
    //
}

//Notify PDU status OFF, block
block HIFI_notify_PDU_status_off_block_ops HIFI 7654 {
    string status_FCU = "OFF" in ["ON","OFF"]; //Status of FCU
    string status_LCU = "OFF" in ["ON","OFF"]; //Status of LCU
    string status_WBSV = "OFF" in ["ON","OFF"]; //Status of WBSV
    string status_WBSH = "OFF" in ["ON","OFF"]; //Status of WBSH
    string status_HRSV = "OFF" in ["ON","OFF"]; //Status of HRSV
    string status_HRSH = "OFF" in ["ON","OFF"]; //Status of HRSH
}{
    StartBlock_ops();
    //This has no delay 
    Hifi_HIFI_notify_PDU_status(status_FCU,status_LCU,status_WBSV,status_WBSH,status_HRSV,status_HRSH);
    //Prepare message for operator: we will check whether one particular HK is ON
    if(status_FCU == "OFF") {
        string subsyst_off = "HI_FCU_S";
    }
    if(status_WBSH == "OFF") {
        subsyst_off = "HI_WBSH_S";
    }
    if(status_WBSV == "OFF") {
        subsyst_off = "HI_WBSV_S";
    }
    if(status_HRSH == "OFF") {
        subsyst_off = "HI_HRSH_S";
    }
    if(status_HRSV == "OFF") {
        subsyst_off = "HI_HRSV_S";
    }
    if(status_LCU == "OFF") {
        subsyst_off = "HI_LCU_S";
    }
    mois_tmcheck("Check that the HK parameter " + subsyst_off + " is OFF.");
    delay(1);
}

/////////////////////////////////////////////////////////////////
// Routine for spectral scans
//
// Get the length of the possible frequency steps without recalibration
double procedure GetFNoCalibLength {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency
}{
    double[] nocaliblen = CalibrationReader("fscangroup",["step_nocalib"],band,lo_freq);

    return nocaliblen[0];
}

{int,double,double,double,double,double} obs HifiMappingModeDBSRaster {
    string modeName = "raster";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Mapping - DBS Raster Map slowChop",{data_time,0,0,n_switch_on,0,0,n_pointsperscan,0,n_cycles,load_interval});
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,int} pre_timing = DBSRaster_pre_timing(nlines,npoints,band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_switch_on,n_pointsperscan,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    // Check for NoddingInRaster or NoddingOfRaster
    int scansize = pre_timing{10};
    if(scansize > 1) {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,double,double,int,int,int,int,int} tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        // Dummy call to spacecraft command
        int[] telescopetimes = nodding_of_raster_pointing(false,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        {int,int,int,string,int,double,double,bool,double,double,double,int,int,double,double,int,int,int,double,double,int,int,int,double,double,int,int,int,int} tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",pre_timing,n_cycles);
        telescopetimes = nodding_raster_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,int},bool,double,double} post_timing = DBSRaster_post_timing(pre_timing,telescopetimes,nlines,npoints,n_switch_on,n_cycles,load_interval,false);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    if(scansize > 1) {
        tmpar = DBSMultiRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        // Call telescope command
        telescopetimes = nodding_of_raster_pointing(true,tmpar{0},tmpar{1},tmpar{2},tmpar{3},tmpar{4},tmpar{5},tmpar{6},tmpar{7},tmpar{8},tmpar{9},tmpar{10},tmpar{11},tmpar{12},tmpar{13},tmpar{14},tmpar{15},tmpar{16},tmpar{17},tmpar{18},tmpar{19},tmpar{20},tmpar{21},tmpar{22},tmpar{23});
    } else {
        tpar = DBSRaster_telescope(naifid,onPosition,lineDistance,stepsize,nlines,npoints,band,lo_freq,"",post_timing{1},n_cycles);
        telescopetimes = nodding_raster_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},tpar{19},tpar{20},tpar{21},tpar{22},tpar{23},tpar{24},tpar{25},tpar{26},tpar{27},tpar{28});
    }
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    int initlength = post_timing{1}{11};
    int dangling = post_timing{1}{12};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        DBSRaster_commanding(band,lo_freq,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_cycles,scansize,n_loadinterval,n_load,final_load,startobs,telescopetimes,loadlength,false);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the noise
    //
    // First get additional dead times from instrument
    {double,double,double} tact = DBSRaster_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_seq,n_load,scansize,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBSRaster_performance(band,lo_freq,effResolution,noisevalues,timeTaken,nlines,npoints,n_cycles,n_seq * imax(n_load,1),tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Stability test, procedure
// Measurement of internal cold in FSW mode
procedure Proc_stability_freqswitch {
    string band = "1a"; // HIFI band
    double lo_freq = 522.0; //The LO frequency
    double freq_throw = 50.0; //The frequency throw in MHz
    int n = 100; //Number of load pairs to be measured
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code
    int integ_time = 4; //Total (co-added) integration time of a phase in sec.
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_cold_ang");
    //Look at CBB
    //
    //Tune to the two frequencies: the first frequency is the one
    //used to tune the backends
    //
    //Set Diplexer to the one corresponding to the middle frequency
    Set_Diplexer_current_FSW_block_fm(band,lo_freq + freq_throw / 2000.0);
    //
    //Set to FSW1
    LO_tuning_FSW_block_fm(band,lo_freq,lo_freq + freq_throw / 2000.0,true);
    //The frequency settings are automatically stored in register FSW1
    //
    //Configure backends
    if(backend == "hrs" || backend == "both" || backend == "hrsFast") {
        HRS_config_block_fm(band,hrs_mode);
        HRS_tune_block_fm(band);
    }
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        //WBS calibration
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    //
    //set to FSW2
    LO_tuning_FSW_block_fm(band,lo_freq + freq_throw / 1000.0,lo_freq + freq_throw / 2000.0,false);
    //The frequency settings are automatically stored in register FSW2
    //
    //Configure spectrometers integration after tuning: done later
    //Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
    //
    Stability_freqswitch_fm(band,n,integ_time,hrs_mode,backend);
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,4,hrs_mode,backend);
    //2 sec. integration
}

//HIFI-COP-3-Deflux
//Systematic deflux at beginning of each OD, or band switch
obs HifiEng_Deflux_COP {
    string band = "1a" in ["ALL","1a","1b","2a","2b","3a","3b","4a","4b"]; // HIFI band. ALL does all mixer bands
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Deflux_COP_proc_ops(band));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Deflux_COP_proc_ops(band);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

{string,double,double}[] procedure HifiPointModeLoadChopNoRefSequencerInit {
    string modeName = "load";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_cycles = 2 in [1,3600]; // number of half load-sky-sky-load cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / effResolution{1},binningexp);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(0.3 * allan_time_lores),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // Contruct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)}];

    return retvalues;
}

/////////////////////////////////////////////////////////////////
// Calibration file reader for spectral scans. This is a variant of the
// CalibrationReader including the dependence on the redundancy instead
// of the LO frequency
//
double[] procedure SpectralScanReader {
    string topicname = "fscanedge"; // Name of entry in master file
    string[] objectnames = ["edgelength"]; // Names of calibration objects to be read
    string band = "4a"; // HIFI band
    int redundancy = 4; // Redundancy factor
}{
    // first step: read master file
    string calibfile = slookup("spectralscan_masterfile",topicname,"filename");
    int dep = ilookup("spectralscan_masterfile",topicname,"dependence");
    string sredun = "" + redundancy;
    int readnum = length(objectnames);
    double[] retvalues = [];
    if(dep == 0) {
        // Quantity is constant
        // Read from single file by name
        for(int i = 1 .. readnum) {
            retvalues[i - 1] = dlookup(calibfile,objectnames[i - 1],"value");
        }
    } else {
        if(dep == 1) {
            // Quantity is only redundancy dependent
            // directly read from file 
            for(int k = 1 .. readnum) {
                retvalues[k - 1] = dlookup(calibfile,sredun,objectnames[k - 1]);
            }
        } else {
            // Quantity is band and redundancy dependent
            // second step step: band look up, get name of responsible data file
            string actualfile = slookup(calibfile,band,"filename");
            // Now lookup data according to redundancy
            for(int j = 1 .. readnum) {
                retvalues[j - 1] = dlookup(actualfile,sredun,objectnames[j - 1]);
            }
        }
    }

    return retvalues;
}

////////////////////////////////////
// Routine to provide initial guesses for sequence parameters
// Load chop observing mode
//
{string,double,double}[] procedure HifiPointProcLoadChopSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    double raoff = 0.0; // RA coordinate of the OFF position
    double decoff = 0.0; // DEC  coordinate of the OFF position
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half load-sky-sky-load cycles on ON
    int n_switch_off = 2 in [1,900]; // number of half load-sky-sky-load cycles on OFF
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF calibration cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    // limit on data rate
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // limits from noise section
    {double,double,double,double} phaselengths = LoadChopPhaseLengths(band,lo_freq,effResolution,oneGHzReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    int n_switch_on_guess = imax(iceil(phaselengths{0} / (2.0 * double(data_time_guess))),1);
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // OFF phase
    int data_time_off_guess = imin(imax(iceil(phaselengths{2}),datalimit),20);
    int data_time_off_range = datalimit - data_time_off_guess;
    if(data_time_off_range == 0) {
        data_time_off_range = 1;
    }
    int n_switch_off_guess = imax(iceil(double(data_time_guess * n_switch_on_guess) / (double(data_time_off_guess) * sqrt(phaselengths{3} / effResolution{1}))),1);
    int n_switch_off_range = 1 - n_switch_off_guess;
    if(n_switch_off_range == 0) {
        n_switch_off_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,2 * n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    new_data_time = MatchMinPointing(data_time_off_guess,data_time_off_range,2 * n_switch_off_guess);
    data_time_off_guess = new_data_time{0};
    data_time_off_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"data_time_off",double(data_time_off_guess),double(data_time_off_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_switch_off",double(n_switch_off_guess),double(n_switch_off_range)}];

    return retvalues;
}

//////////////////////////////////////////////////////////////////
// Procedure to compute detailed pre timing for the version of the
// load chop mode without baseline measurement
// 
{int,int,int,int,int,int,bool,int,int} procedure LoadChopNoRef_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_chop_on = 2 in [1,3600]; // number of half load-sky-sky-load cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    // Compute parameters for the instrument timing
    int on_inttime = 2 * n_chop_on * data_time;
    // compute load integration time
    int loadlength = duration(LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Compare load interval with duration of the observation
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    int n_load_on = on_inttime / load_spacing;
    // This determines the order of the loops
    if(load_spacing > 2 * on_inttime) {
        int n_per_on = n_chop_on;
        bool end_load_on = false;
        int on_pointing = on_inttime + jitterdead;
    } else {
        n_per_on = n_chop_on / (n_load_on + 1);
        if(n_per_on < 1) {
            SError("Chop phase length on source too long relative to load period.");
        }
        end_load_on = true;
        on_inttime = 2 * n_per_on * (n_load_on + 1) * data_time;
        on_pointing = on_inttime + n_load_on * loadlength + jitterdead;
    }
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,false);
    }
    initlength = initlength + loadlength;
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed for telescope call and post_timing processing

    return {on_inttime,on_pointing,loadlength,load_spacing,n_per_on,n_load_on,end_load_on,initlength,dangling};
}

// Wrapper to read configuration parameters for fixed instrument configurations
//
// Procedure for configuration parameters for the WARM instrument 
//
{double,string}[] procedure ConfigurationReaderWarm {
    string topicname = "name_confilfpu"; // Name of entry in master file
    string[] objectnames = ["bias_standby_h"]; // Names of calibration objects to be read
    string band = "1a"; // HIFI band
    double lo_freq = 522000.0; // LO frequency
}{
    string mainmasterfile = "configuration_masterfile_warm";
    {double,string}[] retvalues = FlexibleConfigurationReader(mainmasterfile,topicname,objectnames,band,lo_freq);

    return retvalues;
}

// Broadcast OBSID for gascell operations
procedure StartMode_Gascell {
}{
    //These are ILT-EGSE commands, not ruled by the 2TC/sec.
    //HifiIltEgse_GAS_set_OBS_ID($OBSID);
    //delay(1);
}

//////////////////////////////////////////////////////////////////
// Procedure to compute detailed pre timing for the version of the
// load chop mode without baseline measurement
// 
{int,int,int,int,int,int,bool,int,int} procedure LoadChopNoRef_FCal_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int n_chop_on = 2 in [1,3600]; // number of half load-sky-sky-load cycles on ON
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // First check validity of frequencies
    CheckLOFrequencies(band,lo_freq,lo_freq);
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // First perform consistency checks
    // Check chunk size given by the data rates
    CheckDataTaking(backendreadoutparms,data_time);
    int jitterdead = GetMaxTimeJitter(band,lo_freq);
    // Compute parameters for the instrument timing
    int on_inttime = 2 * n_chop_on * data_time;
    // compute load integration time
    int loadlength = duration(LoadMeasurement_FCal(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Compare load interval with duration of the observation
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    int n_load_on = on_inttime / load_spacing;
    // This determines the order of the loops
    if(load_spacing > 2 * on_inttime) {
        int n_per_on = n_chop_on;
        bool end_load_on = false;
        int on_pointing = on_inttime + jitterdead;
    } else {
        n_per_on = n_chop_on / (n_load_on + 1);
        if(n_per_on < 1) {
            SError("Chop phase length on source too long relative to load period.");
        }
        end_load_on = true;
        on_inttime = 2 * n_per_on * (n_load_on + 1) * data_time;
        on_pointing = on_inttime + n_load_on * loadlength + jitterdead;
    }
    // Duration of initial set up
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,lo_freq,false);
    }
    initlength = initlength + loadlength;
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed for telescope call and post_timing processing

    return {on_inttime,on_pointing,loadlength,load_spacing,n_per_on,n_load_on,end_load_on,initlength,dangling};
}

// Diplexer scan, slow, procedure.
// IF power as function of diplexer current. Takes 3 seconds per point
// Readouts from spectrometers
procedure Diplexer_scan_slow_proc {
    string band = "3a"; // HIFI band //Setting file
    double diplexer_current_min_h = -2.24; //minimum diplexer current H
    double diplexer_current_max_h = 2.24; //maximum diplexer current H
    double diplexer_current_min_v = -2.24; //minimum diplexer current V
    double diplexer_current_max_v = 2.24; //maximum diplexer current V
    int n_steps = 100; //number of steps
    string[] hrs_mode = ["wb1","wb1"]; //HRS resolution code: hr,mr,lr,wb1,wb2,wb3,wb4,etc
    double lo_freq = 807.0; //LO frequency
    int integ_time = 4; //Total integration time in sec.: at least 2sec !  
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
    string chopmode = "tp" in ["tp","slowchop","fastchop"]; //modulation mode between hot/cold: tp, slowchop, fastchop
    double chop_phase = 1.0 in [0.2,2.0]; // Chop phase length
}{
    //In case of band 6 or 7, use special biases
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilfpu",["bias_dipscan_h","bias_dipscan_v","bias_max_h","bias_max_v"],band,lo_freq);
        //First go to 4mV
        Mixerbias_block_fm(result[2]{0},result[3]{0});
        //Then to 3mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //
    Chopper_Rotation_block_fm(band,"chop_M3_ang","chop_hot_ang");
    //Prepare for backend attenuators and calibration
    //ASSUMES HOT LOAD INTERNAL !!
    //Configure and tune backends
    //Shall be done on the worst diplexer setting
    double worst_diplex_current_h = 0.0;
    double worst_diplex_current_v = 0.0;
    //Fetch diplexer settings
    double[] result_dip = Get_Diplexer_setting(band,lo_freq);
    double diplex_H = result_dip[0];
    double diplex_V = result_dip[1];
    //Check which polarisation is used: the unused polarisation has a constant setting
    if(diplexer_current_min_v == diplexer_current_max_v) {
        //H polar is in use
        if(abs(diplex_H - diplexer_current_min_h) > abs(diplex_H - diplexer_current_max_h)) {
            worst_diplex_current_h = diplexer_current_min_h;
        } else {
            worst_diplex_current_h = diplexer_current_max_h;
        }
    }
    if(diplexer_current_min_h == diplexer_current_max_h) {
        //V polar is in use
        if(abs(diplex_V - diplexer_current_min_v) > abs(diplex_V - diplexer_current_max_v)) {
            worst_diplex_current_v = diplexer_current_min_v;
        } else {
            worst_diplex_current_v = diplexer_current_max_v;
        }
    }
    //
    Set_Diplexer_current_block_fm(worst_diplex_current_h,worst_diplex_current_v);
    //
    //Configure backends
    //16/11/05: NOT ANYMORE, THIS SHOULD BE DONE INDEPENDENTLY
    //HRS_config_block_fm(band,hrs_mode);
    //WBS_config_block_fm(band);
    //WBS calibration
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        WBS_calib_fm(band);
        WBS_tune_proc_fm(band);
    }
    if(backend == "hrs" || backend == "both") {
        HRS_tune_block_fm(band);
    }
    //
    //Configure spectrometers integration after tuning
    int[] res = [0,0];
    int n_wbs1 = 0;
    int n_hrs_trans = 0;
    int total_time = 0;
    if(chopmode == "tp") {
        res = Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
        total_time = res[0] * res[1];
    }
    if(chopmode == "slowchop") {
        res = Configure_Spectrometer_hc_slow_chop_proc_fm(band,integ_time * 2,hrs_mode,backend);
        total_time = res[0] * res[1];
    }
    if(chopmode == "fastchop") {
        //Integ_time expected here is the TOTAL integration time with both phases + residual HRS time
        res = Configure_Spectrometer_fast_chop_proc_fm(band,integ_time * 2,chop_phase,hrs_mode,backend);
        total_time = iceil(chop_phase * double(res[1] * res[2]));
        n_wbs1 = res[2];
        n_hrs_trans = res[3];
        //debug_print("Fast chop parameters: n_wbs1 = "+res[2]+", n_hrs_trans = "+res[3]);
    }
    //
    //Start loop on diplexer settings
    int steps = 0;
    int steps_done = 0;
    int steps_wanted = n_steps;
    if(steps_wanted < 1) {
        steps_wanted = 1;
    }
    double diplexer_current_h = 0.0;
    double diplexer_current_v = 0.0;
    double stepsize_h = 0.0;
    double stepsize_v = 0.0;
    //
    if(steps_wanted > 1) {
        stepsize_h = (diplexer_current_max_h - diplexer_current_min_h) / (double(steps_wanted) - 1.0);
        stepsize_v = (diplexer_current_max_v - diplexer_current_min_v) / (double(steps_wanted) - 1.0);
    }
    while(steps_done < steps_wanted) {
        steps = steps_wanted - steps_done;
        if(steps > n_steps) {
            steps = n_steps;
        }
        diplexer_current_h = diplexer_current_min_h + double(steps_done) * stepsize_h;
        diplexer_current_v = diplexer_current_min_v + double(steps_done) * stepsize_v;
        Set_Diplexer_current_block_fm(diplexer_current_h,diplexer_current_v);
        //Y-factor
        Hot_cold(band,hrs_mode,backend,total_time,chopmode,n_wbs1,n_hrs_trans);
        //
        steps_done = steps_done + 1;
    }
    //Get back to optimal settings
    Set_Diplexer_current_block_fm(diplex_H,diplex_V);
    //
    //In case of band 6 or 7,go back to nominal values
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        //First go to 4mV
        Mixerbias_block_fm(result[0]{0},result[1]{0});
        //Then to nominal
        result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias_block_fm(result[0]{0},result[1]{0});
    }
    //
    //Configure spectrometers integration back to default in tp mode
    Configure_Spectrometer_proc_fm(band,integ_time,hrs_mode,backend);
}

/////////////////////////////////////////////////////////////////
// Fast chop dual beam switch observing mode - special version for Jupiter
//
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiPointProcJupiterFastDBS {
    /* Setup parameters */
    int naifid = 0; // Tracing object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 10 in [4,80]; // data dump interval
    int n_int_on = 20 in [1,640]; // number chop cycles to integrate in ICU before transfer
    int n_switch_on = 1 in [1,1800]; // number of data transfer cycles per pointing
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Engineering - Jupiter - DBS fastChop",{data_time,0,n_int_on,n_switch_on,0,0,0,0,n_cycles,load_interval});
    // Call first part of the timing computer
    // Two changes relative to the normal DBS 
    // 1) The longer load duration is enforced by zero resolution
    {double,double} loadResolution = {0.0,effResolution{1}};
    // 2) I assume that the tuning duration does not depend on the tuning level
    // so that the normal pre_timing can be reused.
    {int,int,int,int,int,int,int,int,int,bool,int,int,int} pre_timing = FastDBS_pre_timing(band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_switch_on,n_cycles,load_interval,docommands);
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",pre_timing,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},bool,double,double} post_timing = DBS_post_timing(pre_timing,telescopetimes,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",post_timing{1},n_cycles);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    int loadlength = post_timing{1}{3};
    int n_load = post_timing{1}{6};
    int n_loadinterval = post_timing{1}{7};
    int n_seq = post_timing{1}{8};
    bool end_load = post_timing{1}{9};
    int shiftlength = post_timing{1}{10};
    bool final_load = post_timing{2};
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        JupiterFastDBS_commanding(band,lo_freq,loadResolution,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,n_loadinterval,end_load,final_load,startobs,telescopetimes,loadlength,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = FastDBS_deadtimes(band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,n_int_on,n_seq,n_load,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,continuumDetection,oneGHzReference,n_cycles,tscan,tact);
    // Evaluate performance
    DBS_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,n_seq * n_int_on * (n_load + 1),tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Continuous HIFI integration with given backend settings at line scan
block HIFIContOtfIntegration HIFI 6023 {
    int n_int = 1; // Integration time counter
    int data_time = 4; // Integration time between two data readouts
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_tp_proc_aot(n_int,data_time,rates);
}

// Fast chop integration OFF-ON-OFF-ON... with telescope at ON position
block HIFIFastChopOnIntegration HIFI 6042 {
    int data_time = 4; // Integration time between two data readouts
    int n_cycle = 1; // readout cycle number
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    int[] parms = [1,0]; // Parameters for chop cycles
    double[] rates = [120.0,1.0,2.0]; // Data rates between and during integrations
}{
    HIFI_Spectr_fast_chop_proc_aot(data_time,n_cycle,band,lo_freq,["chop_M3left","chop_M3right"],parms,rates);
}

// Set diplexer currents for both polarizations, block
block Set_Diplexer_current_block_fm HIFI 3643 {
    double dipl_curr_h = 1.0; //Diplexer current H polarization
    double dipl_curr_v = 1.0; //Diplexer current V polarization
}{
    //Start_block();
    Hifi_HIFI_CH1_DPACT_C($BBID,dipl_curr_h);
    Hifi_HIFI_CV1_DPACT_C($BBID,dipl_curr_v);
    delay(1);
}

///////////////////////////
//OBSOLETE
// Stability test, procedure, only backends
procedure Proc_stability_backend_fastchop {
}{
    error("Stability_backend_fastchop_fm mode is removed. Do not use");
}

/////////////////////////////////////////////////////////////////
// Spectral scan in DBS observing modes
// 
// Combination of four modules implementing the new structure 
//
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiSScanProcDBS {
    /* Setup parameters */
    int naifid = 0; // Tracing object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4 in [1,12]; // Frequency scan redundancy
    {double,double} effResolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool wbs1Used = true; // whether WBS1  is used
    bool wbs2Used = true; // whether WBS2  is used 
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int n_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = true; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Spectral Scan - DBS slowChop",{data_time,0,0,n_switch_on,0,0,0,n_freq_point,n_cycles,load_interval});
    // First get the backend configuration
    {{bool,int,double[],bool[]},{bool,int,double[],bool[]},{bool,int[][]},{bool,int[][]}} backends = SScanBackendSettings(band,redundancy,wbs1Used,wbs2Used,data_time);
    {bool,int,double[],bool[]} hr1 = backends{0};
    {bool,int,double[],bool[]} hr2 = backends{1};
    {bool,int[][]} wb1 = backends{2};
    {bool,int[][]} wb2 = backends{3};
    //////////////////////////////////////////////////////////////////////
    // Call first part of the timing computer
    {{int,int,int,int,int,int,int,int,int,bool,int,int,int},{int,double,double[],int[][],bool,double[],int,bool}} pre_timing = SScanDBS_pre_timing(band,lo_freq,lo_freq_up,redundancy,effResolution,hr1,hr2,wb1,wb2,data_time,n_switch_on,n_freq_point,n_cycles,load_interval,docommands);
    // frequency parameters
    int groupnumber = pre_timing{1}{0};
    double reffreq = pre_timing{1}{1};
    double[] freqgrid = pre_timing{1}{2};
    int[][] grouporder = pre_timing{1}{3};
    bool retuning = pre_timing{1}{4};
    double[] targetlevels = pre_timing{1}{5};
    int nfreq_if = pre_timing{1}{6};
    bool dsb = pre_timing{1}{7};
    int n_total = groupnumber * n_cycles;
    //////////////////////////////////////////////////////////////////////
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar = DBS_telescope(naifid,onPosition,band,reffreq,"",pre_timing{0},n_total);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    //////////////////////////////////////////////////////////////////////
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},double,double,double} post_timing = SScanDBS_post_timing(pre_timing{0},telescopetimes,n_freq_point,groupnumber,n_cycles,false);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,reffreq,"",post_timing{1},n_total);
    // Call telescope command
    telescopetimes = nodding_pointing(true,tpar{0},tpar{1},tpar{2},tpar{3},tpar{4},tpar{5},tpar{6},tpar{7},tpar{8},tpar{9},tpar{10},tpar{11},tpar{12},tpar{13},tpar{14},tpar{15},tpar{16},tpar{17},tpar{18},false);
    // Consistency check
    int totaltime = post_timing{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following 
    // normal pre_timing values
    int n_loadinterval = post_timing{1}{7};
    int n_bchop = post_timing{1}{8};
    int shiftlength = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    double avnumchop = post_timing{2};
    // efficiency parameters
    double tscan = post_timing{3};
    double tdead = post_timing{4};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    ///////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        SScanDBS_commanding(band,reffreq,effResolution,hr1,hr2,wb1,wb2,n_freq_point,grouporder,freqgrid,retuning,targetlevels,data_time,n_cycles,n_total,n_bchop,n_switch_on,n_loadinterval,startobs,telescopetimes,shiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double} tact = SScanDBS_deadtimes(band,reffreq,hr1,hr2,wb1,wb2,n_freq_point,data_time,n_bchop,n_switch_on,n_cycles,avnumchop,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = SScanDBS_noisecomputer(band,reffreq,nfreq_if,dsb,effResolution,continuumDetection,n_cycles,tscan,tact);
    // Evaluate performance
    SScanDBS_performance(band,reffreq,nfreq_if,dsb,effResolution,noisevalues,timeTaken,n_total,groupnumber * n_freq_point,avnumchop,tscan,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Conversion from string band name to band code (index)
// for further use in LSU frequency setting
// DT - 22 Aug 2006
double procedure GetBandCode {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //Loop on band names
    double band_code = 1.0;
    if(band == "1b") {
        //Band 1b
        band_code = 2.0;
    }
    if(band == "2a") {
        //Band 2a
        band_code = 3.0;
    }
    if(band == "2b") {
        //Band 2b
        band_code = 4.0;
    }
    if(band == "3a") {
        //Band 3a
        band_code = 5.0;
    }
    if(band == "3b") {
        //Band 3b
        band_code = 6.0;
    }
    if(band == "4a") {
        //Band 4a
        band_code = 7.0;
    }
    if(band == "4b") {
        //Band 4b
        band_code = 8.0;
    }
    if(band == "5a") {
        //Band 5a
        band_code = 9.0;
    }
    if(band == "5b") {
        //Band 5b
        band_code = 10.0;
    }
    if(band == "6a") {
        //Band 6a
        band_code = 11.0;
    }
    if(band == "6b") {
        //Band 6b
        band_code = 12.0;
    }
    if(band == "7a") {
        //Band 7a
        band_code = 13.0;
    }
    if(band == "7b") {
        //Band 7b
        band_code = 14.0;
    }
    // 

    return band_code;
}

////////////////////////////////////
// Function to estimate the initial overhead used within CUS
// 
// From the current implementation of the pointing modes it seems
// that the initail slew is never used as part of the total time
// This needs confirmation for cases with tuning+load > required slew
int procedure InitialCusOverhead {
    /* Setup parameters */
    {double,double} onPosition = {0.0,0.0}; // Coordinates of the source
    {double,double} refPosition = {0.2,0.2}; // Coordinates of the OFF position
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int clustered = 0; // whether observation is part of spatial/frequency cluster
    int data_time = 4; // data dump interval limited by the data rates; a value of 0 will be interpreted as fast-chop mode where we use a default rate
}{
    //////////////////////////////////////////////////////////////////////
    // Call timing computer
    //
    // With the new pointing modes the initial overhead is always
    // excluded from the total observing time now
    //
    // int timing=Overhead_timing(
    //		onPosition,refPosition,band,lo_freq,effResolution,
    //		hrs1,hrs2,wbs1,wbs2,clustered,data_time);
    int timing = 0;

    return timing;
}

//  WBS overall attenuator FM functional test, block
block FT_WBS_att_individual_COMB_fm HIFI 3715 {
    string band = "1a"; // HIFI band
    int integ_time = 4; //Total integration time in sec.
    string laser_H = "Laser1" in ["Laser1","Laser2"]; //WBS-H laser to be set ON
    string laser_V = "Laser1" in ["Laser1","Laser2"]; //WBS-V laser to be set ON
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Start_block(); 
    //
    //Set zero and comb off
    Hifi_HIFI_Single_cmd($BBID,"HWH_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_ZERO_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWH_COMB_ON");
    Hifi_HIFI_Single_cmd($BBID,"HWV_COMB_ON");
    delay(2);
    //
    //Initial configuration: overall attenuators set to 0, individual attenuators to max.
    //H-Polarization
    //
    {double,string}[] result = ConfigurationReader("name_configwbs",["hwh_heater","hwh_latchup_s"],band,0.0);
    string hwh_laser1_s = "OFF";
    string hwh_laser2_s = "OFF";
    if(laser_H == "Laser1") {
        hwh_laser1_s = "ON";
    }
    if(laser_H == "Laser2") {
        hwh_laser2_s = "ON";
    }
    int hwh_heater = iround(result[0]{0});
    string hwh_latchup_s = result[1]{1};
    int hwh_att_band4 = 8;
    int hwh_att_band3 = 8;
    int hwh_att_band2 = 8;
    int hwh_att_band1 = 8;
    int hwh_att_in = 7;
    //
    result = ConfigurationReader("name_delays",["wbs_config_delay"],band,0.0);
    int wbs_config_delay = iround(result[0]{0});
    //
    //V-Polarization
    //
    result = ConfigurationReader("name_configwbs",["hwv_heater","hwv_latchup_s"],band,0.0);
    string hwv_laser1_s = "OFF";
    string hwv_laser2_s = "OFF";
    if(laser_V == "Laser1") {
        hwv_laser1_s = "ON";
    }
    if(laser_V == "Laser2") {
        hwv_laser2_s = "ON";
    }
    int hwv_heater = iround(result[0]{0});
    string hwv_latchup_s = result[1]{1};
    int hwv_att_band4 = 8;
    int hwv_att_band3 = 8;
    int hwv_att_band2 = 8;
    int hwv_att_band1 = 8;
    int hwv_att_in = 7;
    //       
    //Loop on overall attenuators
    for(int i = 0 .. 7) {
        // Change the value of the individual attenuators
        //===============================================
        hwh_att_band4 = hwh_att_band4 - 1;
        hwh_att_band3 = hwh_att_band3 - 1;
        hwh_att_band2 = hwh_att_band2 - 1;
        hwh_att_band1 = hwh_att_band1 - 1;
        hwv_att_band4 = hwv_att_band4 - 1;
        hwv_att_band3 = hwv_att_band3 - 1;
        hwv_att_band2 = hwv_att_band2 - 1;
        hwv_att_band1 = hwv_att_band1 - 1;
        // Set WBS
        //========
        Hifi_HIFI_Configure_WBS_H($BBID,hwh_laser1_s,hwh_laser2_s,hwh_heater,hwh_latchup_s,hwh_att_band4,hwh_att_band3,hwh_att_band2,hwh_att_band1,hwh_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        Hifi_HIFI_Configure_WBS_V($BBID,hwv_laser1_s,hwv_laser2_s,hwv_heater,hwv_latchup_s,hwv_att_band4,hwv_att_band3,hwv_att_band2,hwv_att_band1,hwv_att_in);
        delay(wbs_config_delay);
        //Wait for configuration to be applied
        //
        HIFI_Spectr_total_power_proc_fm(band,backend,integ_time);
        //
    }
    //Set att. to max.
    WBS_config_proc_max_att_w_laser_fm(band,laser_H,laser_V);
    //
}

// Vector scan calibration for a given LO band
// uses a list of pre-defined frequencies where to measure
// the vector scans.
procedure Vecscan_calibration_proc_fm {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //
    //Get list of frequencies for given band
    double[] cresult = CalibrationReader("name_keyfreq",["keyfreq","minfreq","maxfreq","midfreq","badfreq"],band,0.0);
    //      
    string current_subband = "0";
    //Start loop on vector scans
    for(int i = 0 .. 4) {
        //Configure FPU at that frequency
        Init_MSA_fm(band,"CLOSE",cresult[i],"ON");
        //
        //Perform vector scan within BLUE limits at that frequency
        Vector_scan_BLUE_LIMIT_block_fm(band,cresult[i]);
        //LCU_CLEAR_ERROR_block_fm();
        //
    }
    //
}

//HIFI vector scan, block
//Does a vector scan around the best D2 guess from vectorscan_BLUE_LIMIT
block Vector_scan_AroundBestGuess_block_fm HIFI 3673 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
}{
    //Clear potential failure mode
    Set_LO_Nominal_proc_fm();
    //
    //Start_block(); 
    //Fetch LO parameters
    string name_configlo = "name_configlo_a";
    string name_configlcu = "name_configlcu_a";
    string name_confindex = "name_confindex_a";
    string name_configlotune = "name_configlotune_a";
    string name_configlcutune = "name_configlcu_a";
    if(band == "1b" || band == "2b" || band == "3b" || band == "4b" || band == "5b" || band == "6b" || band == "7b") {
        name_configlo = "name_configlo_b";
        name_configlcu = "name_configlcu_b";
        name_confindex = "name_confindex_b";
        name_configlotune = "name_configlotune_b";
        name_configlcutune = "name_configlcu_b";
    }
    //
    {double,string}[] result = ConfigurationReader(name_configlcu,["plevel_v","m1_v","m2_v","m3_v","d2_step"],band,lo_freq);
    double plevel_v = result[0]{0};
    double m1_v = result[1]{0};
    double m2_v = result[2]{0};
    double m3_v = result[3]{0};
    int d2_step = iround(result[4]{0});
    //
    double[] cresult = CalibrationReader("name_lcu_safe_values",["g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double gate1_v = cresult[0];
    double gate2_v = cresult[1];
    double drain1_v = cresult[2];
    double drain2_v_start = cresult[3];
    //
    result = ConfigurationReader(name_confindex,["freq_nx"],band,lo_freq);
    int freq_nx = ifloor(result[0]{0});
    //Compute lsu_main and offset
    int[] resu = ComputeLSU_A_M_R(band,lo_freq);
    int lsu_main = resu[0];
    int lsu_offset = resu[1];
    //Get checksum
    result = ConfigurationReader("name_delays",["cus_checksum"],band,lo_freq);
    int macro_checksum = iround(result[0]{0});
    //
    cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,lo_freq);
    double drain2_safe = cresult[0];
    //
    //The best guess is taken from look-up table
    result = ConfigurationReader(name_configlcutune,["drain2_v"],band,lo_freq);
    double drain2_bestguess = result[0]{0};
    //We will scan +/- 5% around the best guess
    drain2_v_start = drain2_bestguess * 0.95;
    if(drain2_v_start < drain2_safe) {
        drain2_v_start = drain2_safe;
    }
    double drain2_max = drain2_bestguess * 1.05;
    double drain2_bluemax = Get_BLUE_LIMIT_D2_proc_fm(band,lo_freq);
    if(drain2_max > drain2_bluemax) {
        drain2_max = drain2_bluemax;
    }
    //
    //
    result = ConfigurationReader(name_configlo,["curlim1_v","curlim2_v"],band,lo_freq);
    string curlim1 = result[0]{1};
    string curlim2 = result[1]{1};
    //
    result = ConfigurationReader(name_configlotune,["step_drain2_v","nsteps","step_time"],band,lo_freq);
    int nsteps = iround(result[1]{0});
    double step_drain2_v = (drain2_max - drain2_v_start) / double(nsteps);
    //result[0]{0};
    double step_time = 5.0;
    //result[2]{0};
    //We will scan from max to min
    drain2_v_start = drain2_max;
    step_drain2_v = -1.0 * step_drain2_v;
    //
    double step_PL_C = 0.0;
    double step_m1_v = 0.0;
    double step_m2_v = 0.0;
    double step_m3_v = 0.0;
    double step_gate1_v = 0.0;
    double step_gate2_v = 0.0;
    double step_drain1_v = 0.0;
    //
    //First we will set the LO to the max of the scan, and wait 20 sec to settle.
    result = ConfigurationReader("name_delays",["config_lo_delay"],band,lo_freq);
    int config_lo_delay = iround(result[0]{0});
    //Send command
    HIFI_Configure_LCU_proc_fm(band,lo_freq,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_max,curlim2,macro_checksum,config_lo_delay);
    //
    delay(20);
    //to settle at this value
    //For bands 1 to 5, scan will be done with increasing drain2 voltages
    //
    //For bands 6 to 7, scan will be done with decreasing drain2 voltages
    if(band == "6a" || band == "7a" || band == "6b" || band == "7b") {
        //step_drain2_v = -1.0*step_drain2_v;
        //drain2_v_start = drain2_max;
    }
    //
    //Load vector scan
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Load_vector_safe_1a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Load_vector_safe_1b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Load_vector_safe_2a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Load_vector_safe_2b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Load_vector_safe_3a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Load_vector_nom_3b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Load_vector_safe_4a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Load_vector_safe_4b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v_start,curlim2,macro_checksum,step_drain2_v);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Load_vector_nom_5a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Load_vector_nom_5b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Load_vector_nom_6a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_m3_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Load_vector_nom_6b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Load_vector_nom_7a($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Load_vector_nom_7b($BBID,nsteps,step_time,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1,drain2_v_start,curlim2,step_PL_C,step_m1_v,step_m2_v,step_gate1_v,step_gate2_v,step_drain1_v,step_drain2_v);
    }
    //
    //delay(1);
    //Execute vector scan 
    Hifi_HIFI_vector_scan($BBID);
    double time_needed = double(nsteps) * step_time;
    delay(iround(time_needed + 2.0 + 0.5));
    //0.5s added for completion of load_vector
    //Additional read of TM pages
    LCU_Read_TM_pages_proc_fm();
}

//////////////////////////////////////////////////////////////////////
// Procedure to perform the noise level evaluation for the observing mode
{double,double,double,double,double} procedure LoadChop_noisecomputer {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    int on_inttime = 16; // Integration time per ON phase
    int off_inttime = 16; // Integration time per OFF phase
    int n_cycles = 1; // Number of half OFF-ON-ON-OFF calibration cycles
    double tscan = 60.0; // Total average duration of one scan
    {double,double,double,double,double} tact = {10.0,4.9,4.9,0.05,0.05}; // Field of actual dead and integration times
}{
    double tdead = tact{0};
    // Average total dead time in one scan
    double inttimeperonphase = tact{1};
    // Actual integration time in ON phase
    double inttimeperoffphase = tact{2};
    // Actual integration time in OFF phase
    double deadtimeperonphase = tact{3};
    // Dead time per switch phase on ON
    // Get parameters which are needed
    double tsys = InterpolateTsys(band,lo_freq);
    double eta_mb = InterpolateCoupling(band,lo_freq);
    double[] gssb = InterpolateGssb(band,lo_freq);
    // Get the drift parameters to compute the drift noise
    // System Allan variance
    double[] allanparms = InterpolateSpecAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double alpha = allanparms[1];
    double binningexp = 1.0 / allanparms[2];
    double allan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double allan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // Differential Allan variance
    allanparms = InterpolateSpecLChopAllan(band,lo_freq,oneGHzReference);
    // rescale to frequency resolution
    double dalpha = allanparms[1];
    binningexp = 1.0 / allanparms[2];
    double dallan_time_lores = allanparms[0] * pow(1.0 / eff_resolution{1},binningexp);
    double dallan_time_hires = allanparms[0] * pow(1.0 / eff_resolution{0},binningexp);
    // resolution of OFF phase
    double sw_resolution = GetLoadChopSWResolution(band,lo_freq);
    double sw_resolution_lores = max(eff_resolution{1},sw_resolution);
    double sw_resolution_hires = max(eff_resolution{0},sw_resolution);
    // Compute the relative noise for the detailed timing
    double on_int = double(on_inttime);
    double off_int = double(off_inttime);
    // The dead time per switch might deviate between ON and OFF - ignored
    double deadtimeperswitch = deadtimeperonphase;
    // Get actual noise
    // This is returned twice: for both limiting resolutions
    double systemnoise_lores = DoubleDifferenceNoise(inttimeperonphase / allan_time_lores,[inttimeperoffphase / inttimeperonphase,sw_resolution_lores / eff_resolution{1},on_int / allan_time_lores,off_int / allan_time_lores,deadtimeperswitch / allan_time_lores,tdead / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    double systemnoise_hires = DoubleDifferenceNoise(inttimeperonphase / allan_time_hires,[inttimeperoffphase / inttimeperonphase,sw_resolution_hires / eff_resolution{0},on_int / allan_time_hires,off_int / allan_time_hires,deadtimeperswitch / allan_time_hires,tdead / allan_time_hires,alpha,dallan_time_hires / allan_time_hires,dalpha]);
    double noiseratio = DoubleDifferenceNoiseRatio(inttimeperonphase / allan_time_lores,[inttimeperoffphase / inttimeperonphase,sw_resolution_lores / eff_resolution{1},on_int / allan_time_lores,off_int / allan_time_lores,deadtimeperswitch / allan_time_lores,tdead / allan_time_lores,alpha,dallan_time_lores / allan_time_lores,dalpha]);
    // Compute total double sideband noise 
    double dsbnoise_lores = tsys * sqrt(systemnoise_lores / (eff_resolution{1} * 1000000.0 * double(n_cycles) * tscan));
    double dsbnoise_hires = tsys * sqrt(systemnoise_hires / (eff_resolution{0} * 1000000.0 * double(n_cycles) * tscan));
    // Translate to the main beam scale, correct for eta_mb
    // (This is typically not done at ground based telescopes,
    //  but leads often to problems there - to be discussed.)
    dsbnoise_lores = dsbnoise_lores / eta_mb;
    dsbnoise_hires = dsbnoise_hires / eta_mb;
    // Get single sideband noise equivalent
    double usbnoise_lores = dsbnoise_lores / gssb[0];
    double usbnoise_hires = dsbnoise_hires / gssb[0];
    double lsbnoise_lores = dsbnoise_lores / gssb[1];
    double lsbnoise_hires = dsbnoise_hires / gssb[1];
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {usbnoise_lores,usbnoise_hires,lsbnoise_lores,lsbnoise_hires,noiseratio};
}

////////////////////////////////////
// DBS raster observing mode
// 
// Return time and noise levels
{string,double,double}[] procedure HifiMappingProcDBSRasterSequencerInit {
    /* Setup parameters */
    int naifid = 0; // Tracking object ID
    double ra = 0.0; // RA coordinate of the source
    double dec = 0.0; // DEC coordinate of the source
    {double,double} lineDistance = {0.0050,0.0050}; // Distance between subsequent rows
    int nlines = 1 in [1,100]; // Number of rows in the map
    double stepsize = 0.0050 in [5.5556E-4,0.13333]; // Distance between subsequent points in the raster line
    int npoints = 10 in [2,100]; // Number of points per row
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} effResolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    bool continuumDetection = false; // Whether timing is for total-power level
    bool oneGHzReference = true; // 1GHz reference bandwith instead of full IF
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_switch_on = 2 in [1,900]; // number of half sky1-sky0-sky0-sky1 cycles per pointing
    int n_pointsperscan = 1 in [1,1024]; // Number of points measured before moving to the second pointing phase
    int n_cycles = 1 in [1,32]; // Number of half OFF-ON-ON-OFF pointing cycles
    int load_interval = 1800 in [10,7200]; // load period = f(band,lo_freq,effResolution{1})
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    int datalimit = dataparms{0};
    // Get the drift parameters to compute the drift noise
    {double,double} phaselengths = DBSPhaseLengths(band,lo_freq,effResolution,continuumDetection,oneGHzReference);
    // Compute derived quantities
    int data_time_guess = imin(imax(iceil(phaselengths{1}),datalimit),20);
    int data_time_range = datalimit - data_time_guess;
    if(data_time_range == 0) {
        data_time_range = 1;
    }
    // Combine points for n_switch=1
    int main_phase = iceil(phaselengths{0});
    int n_pointsperscan_guess = imin(imax(main_phase / (2 * data_time_guess),1),npoints * nlines);
    int n_pointsperscan_range = 1 - n_pointsperscan_guess;
    if(n_pointsperscan_range == 0) {
        n_pointsperscan_range = 1;
    }
    // remaining part for n_switch
    int n_switch_on_guess = main_phase / (n_pointsperscan_guess * 2 * data_time_guess) + 1;
    int n_switch_on_range = 1 - n_switch_on_guess;
    if(n_switch_on_range == 0) {
        n_switch_on_range = 1;
    }
    // Add pointing requirements condition: >=10s
    {int,int} new_data_time = MatchMinPointing(data_time_guess,data_time_range,2 * n_switch_on_guess);
    data_time_guess = new_data_time{0};
    data_time_range = new_data_time{1};
    // Construct return tuple
    {string,double,double}[] retvalues = [{"data_time",double(data_time_guess),double(data_time_range)},{"n_switch_on",double(n_switch_on_guess),double(n_switch_on_range)},{"n_pointsperscan",double(n_pointsperscan_guess),double(n_pointsperscan_range)}];

    return retvalues;
}

//Find out stepsize
double procedure Stepsize {
    double low = 0.0;
    double high = 10.0;
    int n_steps = 100;
    string parameter = "hifi_HIF_mx_mg_step_C";
}{
    double range = high - low;
    int range_raw = convert_to_raw(parameter,range);
    if(range_raw < 1) {
        range_raw = 1;
    }
    double bitsize = range / double(range_raw);
    int step_raw = iround(double(range_raw) / double(n_steps));
    if(step_raw == 0) {
        step_raw = 1;
    }
    double step = double(step_raw) * bitsize;

    return step;
}

//TPF maker for LCU patch and checksum recalc
procedure LCU_patch_TPF_maker {
    string section = "P" in ["P","R"];
}{
    //Patch upload: 150 FP involved
    //{int, int[]}[] runs = LcuGetMemoryRuns_ops( section);
    {int,int[]}[] runs = LcuGetMemoryRuns(section,1);
    int runcount = length(runs);
    if(runcount > 50) {
        error("LCU memory patch has more than 50 lines. This will not fit in the procedure.");
    }
    if(runcount != 0) {
    } else {
        //Empty patch
    }
    for(int i = 0 .. runcount - 1) {
        {int}[] par = [];
        int[] values = runs[i]{1};
        int count = length(values);
        for(int j = 0 .. count - 1) {
            par[j] = {values[j]};
        }
        int val = par[0]{0};
        int crc = checksum("short",values);
        //Cannot use the Hifi_HIFI_load_LCU because tupples not supported in TPF generation
        Hifi_HIFI_WBS_Zero(runs[i]{0});
        //Call from Ralph 04/03/09: group repeaters can be declared as FP
        //This value is 1 anyway
        //Hifi_HIFI_WBS_Zero(count);
        Hifi_HIFI_WBS_Zero(val);
        Hifi_HIFI_WBS_Zero(crc);
        //delay(2);
    }
    //Complement the number of TCs sent to reach the fixed TC pattern needed for TPF
    int nb_TC_needed = 50;
    //subjective choice - may be extended in the future
    int remaining_TC = nb_TC_needed - runcount;
    //Compute parameters for constant inputs
    values = runs[0]{1};
    count = length(values);
    for(int jj = 0 .. count - 1) {
        par[jj] = {values[jj]};
    }
    val = par[0]{0};
    crc = checksum("short",values);
    for(int ii = 1 .. remaining_TC) {
        //Cannot use the Hifi_HIFI_load_LCU because tupples not supported in TPF generation
        Hifi_HIFI_WBS_Zero(runs[0]{0});
        //Call from Ralph 04/03/09: group repeaters can be declared as FP
        //This value is 1 anyway
        //Hifi_HIFI_WBS_Zero(count);
        Hifi_HIFI_WBS_Zero(val);
        Hifi_HIFI_WBS_Zero(crc);
        //delay(2);           
    }
    //
}

//Magnet tune coarse, procedure
procedure Magnet_tune_coarse {
    string band = "1a"; // HIFI band
}{
    Magnet_scan_coarse_fm(band);
    Magnet_set_coarse_with_IVcurve_fm(band);
}

// Initialisation of FPU, block with both MSA in use
// Looks at the hot load !
// It is for cold context !
block Init_MSA_HBB_fm HIFI 3999 {
    string band = "1a"; // HIFI band
    string chop_loop = "CLOSE";
    double lo_freq = 522.0; //LO frequency
    string hbb_heater = "ON" in ["ON","OFF"]; //hot source on/off
}{
    //Start_block();
    //Get parameters
    {double,string}[] result_d = ConfigurationReader("name_confilfpu",["band","fif1v_h","fif1c_h","fif2v_h","fif2c_h","sif1v_h","sif1c_h","sif2v_h","sif2c_h","sif3v_h","sif3c_h"],band,lo_freq);
    int band_nb = iround(result_d[0]{0});
    double diplex_H = 0.0;
    double diplex_V = 0.0;
    int diplex_h_ctrl_mode = 0;
    int diplex_v_ctrl_mode = 0;
    //
    double volt_H_FIF_1 = result_d[1]{0};
    double curr_H_FIF_1 = result_d[2]{0};
    double volt_H_FIF_2 = result_d[3]{0};
    double curr_H_FIF_2 = result_d[4]{0};
    //
    double volt_H_SIF_1 = result_d[5]{0};
    double curr_H_SIF_1 = result_d[6]{0};
    double volt_H_SIF_2 = result_d[7]{0};
    double curr_H_SIF_2 = result_d[8]{0};
    double volt_H_SIF_3 = result_d[9]{0};
    double curr_H_SIF_3 = result_d[10]{0};
    // 
    result_d = ConfigurationReader("name_confilfpu",["fif1v_v","fif1c_v","fif2v_v","fif2c_v","sif1v_v","sif1c_v","sif2v_v","sif2c_v","sif3v_v","sif3c_v"],band,lo_freq);
    //
    double volt_V_FIF_1 = result_d[0]{0};
    double curr_V_FIF_1 = result_d[1]{0};
    double volt_V_FIF_2 = result_d[2]{0};
    double curr_V_FIF_2 = result_d[3]{0};
    //
    double volt_V_SIF_1 = result_d[4]{0};
    double curr_V_SIF_1 = result_d[5]{0};
    double volt_V_SIF_2 = result_d[6]{0};
    double curr_V_SIF_2 = result_d[7]{0};
    double volt_V_SIF_3 = result_d[8]{0};
    double curr_V_SIF_3 = result_d[9]{0};
    //
    string chop_sine_s = "ON";
    //  string chop_loop = "CLOSE" ;
    result_d = ConfigurationReader("name_confilfpu",["chop_g1","chop_g2","chop_z1","chop_z2","chop_p2","chop_g3","chop_p3","calibrator_current"],band,lo_freq);
    //
    int chop_G1 = iround(result_d[0]{0});
    int chop_G2 = iround(result_d[1]{0});
    int chop_Z1 = iround(result_d[2]{0});
    int chop_Z2 = iround(result_d[3]{0});
    int chop_P2 = iround(result_d[4]{0});
    //
    //
    //  
    double calibcurrent = result_d[7]{0};
    if(hbb_heater == "ON") {
        result_d = ConfigurationReader("name_confilfpu",["calibrator_current_on"],band,lo_freq);
        calibcurrent = result_d[0]{0};
    }
    //
    //Get biases
    result_d = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
    double bias_H = result_d[0]{0};
    double bias_V = result_d[1]{0};
    //For bands 6 and 7, first set to 4mV
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        result_d = ConfigurationReader("name_confilfpu",["bias_max_h","bias_max_v"],band,lo_freq);
        bias_H = result_d[0]{0};
        bias_V = result_d[1]{0};
    }
    //
    //Get magnets: not applicable to bands 6 and 7
    double magnetcurrent_H = 0.0;
    double magnetcurrent_V = 0.0;
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilfpu",["magnet_current_max_h","magnet_current_max_v"],band,lo_freq);
        magnetcurrent_H = result_d[0]{0};
        magnetcurrent_V = result_d[1]{0};
    }
    //Diplexer is interpolated from a table for Bands 3, 4, 6L and 6H
    if(band_nb <= 2 || band_nb == 5) {
        diplex_H = 0.0;
        //For bands 1, 2 and 5
        diplex_V = 0.0;
        diplex_h_ctrl_mode = 0;
        diplex_v_ctrl_mode = 0;
    } else {
        //Get diplexer currents
        result_d = ConfigurationReader("name_confilfpu",["diplex_h_ctrl_mode","diplex_v_ctrl_mode"],band,lo_freq);
        diplex_h_ctrl_mode = iround(result_d[0]{0});
        diplex_v_ctrl_mode = iround(result_d[1]{0});
        double[] result_dip = Get_Diplexer_setting(band,lo_freq);
        diplex_H = result_dip[0];
        diplex_V = result_dip[1];
    }
    //
    result_d = ConfigurationReader("name_confilfpu",["chop_hot"],band,0.0);
    //result_d = ConfigurationReader("name_chopper",["chop_startup_cold"],
    // 						     band,0.0);  
    if(chop_loop == "OPEN") {
        result_d = ConfigurationReader("name_chopper",["chop_startup_warm"],band,0.0);
    }
    double chopper = result_d[0]{0};
    //For this configuration we won't convert prime chopper voltage into redundant voltage
    //Just checking we are in range.
    //chopper = Check_Chopper_Prime_Redundant(chopper);
    chopper = Check_Chopper_Range(chopper);
    //
    //Switch on upconverter, assuming chopper and mixers are also ON
    Hifi_HIFI_Configure_FCU_Power($BBID,"ON","ON","ON","ON","ON");
    //
    HIFI_Configure_FCU_proc_fm(band_nb,diplex_h_ctrl_mode,volt_H_FIF_1,curr_H_FIF_1,volt_H_FIF_2,curr_H_FIF_2,volt_H_SIF_1,curr_H_SIF_1,volt_H_SIF_2,curr_H_SIF_2,volt_H_SIF_3,curr_H_SIF_3,diplex_v_ctrl_mode,volt_V_FIF_1,curr_V_FIF_1,volt_V_FIF_2,curr_V_FIF_2,volt_V_SIF_1,curr_V_SIF_1,volt_V_SIF_2,curr_V_SIF_2,volt_V_SIF_3,curr_V_SIF_3,chop_sine_s,chop_loop,chop_G1,chop_G2,chop_Z1,chop_Z2,chop_P2,calibcurrent,bias_H,magnetcurrent_H,bias_V,magnetcurrent_V,chopper,diplex_H,diplex_V);
    //
    result_d = ConfigurationReader("name_delays",["config_fpu_delay"],band,lo_freq);
    int config_fpu_delay = iround(result_d[0]{0});
    delay(config_fpu_delay);
    //
    //In case of band 6 or 7, bias have been set to 4mV. Now set to nominal
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        {double,string}[] result = ConfigurationReader("name_confilmix",["norm_bias_h","norm_bias_v"],band,lo_freq);
        Mixerbias(result[0]{0},result[1]{0});
    }
    //
    //Magnet are so far at maximum value. Now set to nominal
    if(band != "6a" && band != "6b" && band != "7a" && band != "7b") {
        result_d = ConfigurationReader("name_confilmix",["norm_magn_h","norm_magn_v"],band,lo_freq);
        Hifi_HIFI_CH1_MX_MG_C($BBID,result_d[0]{0});
        Hifi_HIFI_CV1_MX_MG_C($BBID,result_d[1]{0});
        delay(1);
    }
    //
    //Hifi_HIFI_non_periodic_hk_FCU ();
}

{int,double,double,double,double,double} obs HifiPointModeFSwitch {
    string modeName = "fs";
    int goalTime = 180;
    double goalNoise = 0.1;
    bool doingTime = true;
    double ra = 0.0;
    double dec = 0.0;
    double raoff = 0.0;
    double decoff = 0.0;
    bool refSelected = true;
    int naifid = 0;
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string spectrometer = "both";
    bool hrsSeparatePol = false;
    string hrsModeH = "Nominal";
    string hrsModeV = "Nominal";
    double fe_lof_0 = 978.2;
    double fe_hrs1_h_0 = 0.0;
    double fe_hrs2_h_0 = 0.0;
    double fe_hrs3_h_0 = 0.0;
    double fe_hrs4_h_0 = 0.0;
    double fe_hrs1_v_0 = 0.0;
    double fe_hrs2_v_0 = 0.0;
    double fe_hrs3_v_0 = 0.0;
    double fe_hrs4_v_0 = 0.0;
    double fe_eff_res_min_0 = 1.1;
    double fe_eff_res_max_0 = 1.1;
    bool resolutionMhz = true;
    bool singleWbs = false;
    int redundancy = 4;
    bool dbsContinuum = true;
    bool oneGHzReference = true;
    double lo_freq1 = 978.2;
    double lo_freq2 = 979.6;
    bool fullRange = true;
    string fsThrow = "small-negative";
    double flyX = 0.0;
    double flyY = 0.0;
    double flyAngle = 0.0;
    bool flyNyquistSel = false;
    double flyCrossStep = 10.0;
    string crossStepSize = "jitter" in ["jitter","nyquist","10","20","40"];
    /* HSPOT-only parameters beyond this line. */
    bool dbsFast = true;
    bool fastChop = true;
    string frame = "LSR";
    string redshiftFrame = "heliocentric";
    string redshiftType = "redshift";
    double redshift = 0.0;
    string fe_wbs_line_0 = "-No Lines-";
    string fe_wbs_trans_0 = "-No Lines-";
    double fe_wbs_freq_0 = -1.0;
    bool fe_wbs_usb_0 = true;
    string fe_hrs1_h_line_0 = "-No Lines-";
    string fe_hrs1_h_trans_0 = "-No Lines-";
    double fe_hrs1_h_freq_0 = -1.0;
    bool fe_hrs1_h_usb_0 = true;
    string fe_hrs2_h_line_0 = "-No Lines-";
    string fe_hrs2_h_trans_0 = "-No Lines-";
    double fe_hrs2_h_freq_0 = -1.0;
    bool fe_hrs2_h_usb_0 = true;
    string fe_hrs3_h_line_0 = "-No Lines-";
    string fe_hrs3_h_trans_0 = "-No Lines-";
    double fe_hrs3_h_freq_0 = -1.0;
    bool fe_hrs3_h_usb_0 = true;
    string fe_hrs4_h_line_0 = "-No Lines-";
    string fe_hrs4_h_trans_0 = "-No Lines-";
    double fe_hrs4_h_freq_0 = -1.0;
    bool fe_hrs4_h_usb_0 = true;
    string fe_hrs1_v_line_0 = "-No Lines-";
    string fe_hrs1_v_trans_0 = "-No Lines-";
    double fe_hrs1_v_freq_0 = -1.0;
    bool fe_hrs1_v_usb_0 = true;
    string fe_hrs2_v_line_0 = "-No Lines-";
    string fe_hrs2_v_trans_0 = "-No Lines-";
    double fe_hrs2_v_freq_0 = -1.0;
    bool fe_hrs2_v_usb_0 = true;
    string fe_hrs3_v_line_0 = "-No Lines-";
    string fe_hrs3_v_trans_0 = "-No Lines-";
    double fe_hrs3_v_freq_0 = -1.0;
    bool fe_hrs3_v_usb_0 = true;
    string fe_hrs4_v_line_0 = "-No Lines-";
    string fe_hrs4_v_trans_0 = "-No Lines-";
    double fe_hrs4_v_freq_0 = -1.0;
    bool fe_hrs4_v_usb_0 = true;
    bool docommands = true; // Whether instrument commands are generated
    /* Sequence parameters */
    int data_time = 4 in [1,20]; // data dump interval limited by the data rates
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_switch_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on ON
    int n_switch_off = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles on OFF
    int n_cycles = 1 in [1,1200]; // Number of half OFF-ON-ON-OFF calibration cycles
    int load_interval = 1800 in [10,7200]; // load period in seconds
}{
    // start Volkers list
    {double,double} lineDistance = {0.0,0.0};
    int nlines = 1;
    double stepsize = 0.0;
    int npoints = 1;
    double lo_freq = 1000.0;
    double lo_freq_up = 1000.0;
    double av_lo_freq = 1000.0;
    double freq_throw = 0.0;
    double redundancy_C = 4.0;
    {double,double} effResolution = {1.0,1.0};
    bool continuumDetection = true;
    {bool,int,double[],bool[]} hrs1 = {true,1,[1.0],[true]};
    {bool,int,double[],bool[]} hrs2 = {true,1,[1.0],[true]};
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]};
    // int data_time = 1 ;
    // double data_chop = 0.0 ;
    // int n_int_on = 1 ;
    // int n_int_off = 1 ;
    // int n_switch_on = 1 ;
    // int n_switch_off = 1 ;
    // int n_linesperscan = 1 ;
    // int n_pointsperscan = 1 ;
    // int n_freq_point = 1 ;
    // int n_cycles = 1;
    // int load_interval = 1 ; 
    // end of Volkers list
    // start general definitions 
    {int,double,double,double,double,double} result = {1,0.0,0.0,0.0,0.0,0.0};
    double degreesPerRadian = 57.2957795;
    double degreesPerArcmin = 1.0 / 60.0;
    double degreesPerArcsec = 1.0 / 3600.0;
    double factorMHzPerGHz = 1000.0;
    double factorMHzPerkHz = 0.0010;
    // end general definitions
    // start translation
    // frequencies
    lo_freq = fe_lof_0 * factorMHzPerGHz;
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        lo_freq = lo_freq1 * factorMHzPerGHz;
        lo_freq_up = lo_freq2 * factorMHzPerGHz;
        av_lo_freq = 0.5 * (lo_freq + lo_freq_up);
    } else {
        av_lo_freq = lo_freq;
        lo_freq_up = lo_freq;
    }
    redundancy_C = double(redundancy);
    freq_throw = GetTrueFsThrow(band,av_lo_freq,fsThrow);
    // An additional function is needed here to compute the
    // actual LO frequency from the redshift correction
    // This needs to be provided by Mission Planning
    // double lo_shift=function(redshift,frame,redshiftframe);
    // pointing
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    // Setup for maps
    if(modeName == "raster" || modeName == "cross" || modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
        // line distance measured 90deg ccw to lines
        lineDistance = {stepsize * cos(flyAngle / degreesPerRadian),stepsize * -sin(flyAngle / degreesPerRadian)};
        npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // exception handling for raster maps
        if(modeName == "raster") {
            if(npoints > 32 || nlines > 32) {
                IError("Map too large." + " Raster maps are restricted to <= 32x32 points.");
            }
        }
        // special treatment for cross map mode
        if(modeName == "cross") {
            npoints = 3;
            nlines = 2;
            if(crossStepSize == "nyquist") {
                s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
                stepsize = s[0];
            } else {
                s = CalibrationReader("crossstep",[crossStepSize],band,av_lo_freq);
                stepsize = s[0];
            }
        }
    } else {
        npoints = 1;
        nlines = 1;
    }
    // backends	
    // assume none used unless proven otherwise	
    hrs1{0} = false;
    hrs2{0} = false;
    wbs1{0} = false;
    wbs2{0} = false;
    if(spectrometer == "hrs" || spectrometer == "hrsFast" || spectrometer == "both") {
        hrs1{0} = true;
        hrs2{0} = true;
    }
    // no HRS in spectral scan modes - only serendipity backend
    if(modeName == "fs-freq" || modeName == "freq" || modeName == "load-freq") {
        hrs1{0} = false;
        hrs2{0} = false;
        // put minimum resolution explicitely to WBS resolution
        fe_eff_res_min_0 = max(1.1,fe_eff_res_min_0);
    }
    double[] x = CalibrationReader("backendselect",["bestwbs"],band,av_lo_freq);
    int bestWbs = iround(x[0]);
    x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,av_lo_freq);
    int[] stdWbsWindow1 = [iround(x[0]),iround(x[1])];
    int[] stdWbsWindow2 = [iround(x[2]),iround(x[3])];
    int[] stdWbsWindow3 = [iround(x[4]),iround(x[5])];
    int[] stdWbsWindow4 = [iround(x[6]),iround(x[7])];
    if(spectrometer == "wbs" || spectrometer == "both") {
        if(!singleWbs) {
            wbs1{0} = true;
            wbs2{0} = true;
        } else {
            if(bestWbs == 1) {
                wbs1{0} = true;
            } else {
                wbs2{0} = true;
            }
        }
    }
    // for spectral scans
    bool wbs1Used = wbs1{0};
    bool wbs2Used = wbs2{0};
    string[] hrsModes = ["High","Nominal","Low","Wide"];
    if(spectrometer == "hrsFast") {
        bool[][] hrsUseMap = [[true,false,false,false],[true,false,false,false],[true,true,false,false],[true,true,false,false]];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
    }
    hrs1{1} = -1;
    hrs2{1} = -1;
    for(int i = 0 .. 3) {
        if(hrsModeH == hrsModes[i]) {
            hrs1{1} = i;
        }
        if(hrsModeV == hrsModes[i]) {
            hrs2{1} = i;
        }
    }
    // Special treatment for band 6 due to weired definition in HSPOT
    // Check whether IF is out of subband I
    if(stdWbsWindow1[1] - stdWbsWindow1[0] == 0) {
        double mix = 0.8;
        // mixing point relative to Andrew's scale
        hrs1{2} = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2{2} = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1{2} = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2{2} = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    for(int j = 0 .. 3) {
        hrs1{2}[j] = hrs1{2}[j] * factorMHzPerGHz;
        hrs2{2}[j] = hrs2{2}[j] * factorMHzPerGHz;
    }
    hrs1{3} = hrsUseMap[hrs1{1}];
    hrs2{3} = hrsUseMap[hrs2{1}];
    wbs1{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    wbs2{1} = [stdWbsWindow1,stdWbsWindow2,stdWbsWindow3,stdWbsWindow4];
    // resolution 
    effResolution = EffectiveResolution(band,av_lo_freq,{fe_eff_res_min_0,fe_eff_res_max_0},resolutionMhz,wbs1{0},wbs2{0},{hrs1{0},hrs1{1}},{hrs2{0},hrs2{1}});
    continuumDetection = dbsContinuum;
    // no need to translate any sequencer-determined values
    // end of translation
    // end of generic code		
    // Start of observing mode
    OpenMessages("HIFI Single Point - Frequency Switch Ref",{data_time,data_time_off,0,n_switch_on,n_switch_off,0,0,0,n_cycles,load_interval});
    // position switch
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int} pre_timing_ps = FSwitch_pre_timing(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_switch_on,n_switch_off,n_cycles,load_interval,docommands);
    // Prepare telescope command
    {double,double} onPosition = {ra,dec};
    {double,double} refPosition = {raoff,decoff};
    {int,int,int,string,int,double,double,bool,double,double,double,int,double,int,int,int,int,int,int} tpar_ps = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,pre_timing_ps,n_cycles);
    // Dummy call to spacecraft command
    int[] telescopetimes = nodding_pointing(false,tpar_ps{0},tpar_ps{1},tpar_ps{2},tpar_ps{3},tpar_ps{4},tpar_ps{5},tpar_ps{6},tpar_ps{7},tpar_ps{8},tpar_ps{9},tpar_ps{10},tpar_ps{11},tpar_ps{12},tpar_ps{13},tpar_ps{14},tpar_ps{15},tpar_ps{16},tpar_ps{17},tpar_ps{18},true);
    // Call second part of timing computer using results
    // from telescope command
    {int,{int,int,int,int,int,int,int,int,int,int,int,int,bool,bool,int,int},int,bool,double,double} post_timing_ps = DoubleChop_post_timing(pre_timing_ps,telescopetimes,n_cycles);
    // Now the actual observation starts
    // Prepare telescope command
    tpar_ps = PositionSwitch_telescope(naifid,onPosition,refPosition,band,lo_freq,post_timing_ps{1},n_cycles);
    // Call telescope command 
    telescopetimes = nodding_pointing(true,tpar_ps{0},tpar_ps{1},tpar_ps{2},tpar_ps{3},tpar_ps{4},tpar_ps{5},tpar_ps{6},tpar_ps{7},tpar_ps{8},tpar_ps{9},tpar_ps{10},tpar_ps{11},tpar_ps{12},tpar_ps{13},tpar_ps{14},tpar_ps{15},tpar_ps{16},tpar_ps{17},tpar_ps{18},true);
    // Consistency check
    int totaltime = post_timing_ps{0};
    if(totaltime != telescopetimes[0]) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " telescope time of " + telescopetimes[0] + "s detected.");
    }
}{
    //////////////////////////////////////////////////////////////////////
    // Instrument section
    // Get all values from post_timing needed in the following
    //////////////////////////////////////////////////////////////////////
    int on_inttime = post_timing_ps{1}{0};
    int off_inttime = post_timing_ps{1}{1};
    int on_pointing = post_timing_ps{1}{2};
    int off_pointing = post_timing_ps{1}{3};
    int loadlength = post_timing_ps{1}{4};
    int n_loadinterval = post_timing_ps{1}{7};
    int n_per_on = post_timing_ps{1}{8};
    int n_per_off = post_timing_ps{1}{9};
    int n_load_on = post_timing_ps{1}{10};
    int n_load_off = post_timing_ps{1}{11};
    bool end_load_on = post_timing_ps{1}{12};
    bool end_load_off = post_timing_ps{1}{13};
    int initshiftlength = post_timing_ps{2};
    bool final_load = post_timing_ps{3};
    double tscan = post_timing_ps{4};
    double tdead = post_timing_ps{5};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    //////////////////////////////////////////////////////////////////////
    // Don't do anything if docommand=false
    //
    if(docommands) {
        FSwitch_commanding(band,lo_freq,freq_throw,effResolution,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_per_on,n_per_off,n_loadinterval,n_load_on,n_load_off,end_load_on,end_load_off,final_load,startobs,telescopetimes,loadlength,initshiftlength);
    } else {
        delay(telescopetimes[0] + telescopetimes[1]);
    }
    // Second consistency check
    int timeTaken = time() - startobs - telescopetimes[1];
    if(timeTaken != totaltime) {
        CError("Mismatch between instrument time of " + totaltime + "s and" + " command duration of " + timeTaken + "s detected.");
    }
    //////////////////////////////////////////////////////////////////////
    // Compute the total rms we got out of this
    //
    // First get additional dead times from instrument
    {double,double,double,double,double} tact = DoubleChop_deadtimes("fs",band,lo_freq,hrs1,hrs2,wbs1,wbs2,data_time,data_time_off,n_per_on,n_per_off,n_load_on,n_load_off,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = FSwitch_noisecomputer(band,lo_freq,effResolution,oneGHzReference,on_inttime,off_inttime,n_cycles,tscan,tact);
    // Evaluate performance
    DoubleChop_performance(band,lo_freq,effResolution,noisevalues,timeTaken,n_cycles,n_per_on * (n_load_on + 1),n_per_off * (n_load_off + 1),true,tscan,on_pointing,tact);
    // Return everything
    noise_level([noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3}]);
    // Auxiliary construct for HSPOT - return total time and noise values
    // Also return the maximum ratio of drift to radiometric noise

    return {timeTaken,noisevalues{0},noisevalues{1},noisevalues{2},noisevalues{3},noisevalues{4}};
}

// Change LO frequency by a small step in FSW mode
//
// Externally it has to be guaranteed that this never uses a step larger
// than one index in the LO table
procedure HIFIChangeFreqFsw {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 978200.0; // LO frequency ion MHz
    double freq_throw = -40.0; // throw of frequency switch in MHz
}{
    ConfigureFPU(band,lo_freq + freq_throw / 2.0,false);
    HIFITuneFreqNoretuneFsw(band,lo_freq,lo_freq + freq_throw);
}

// procedure called to get the WBS into standby
procedure HifiIntoStandby_II {
}{
    //LO is switched off -> is superfluous if from stbyI to stbyII
    LCU_switch_off_block_aot();
    //Will only switch heaters
    //LO is switched to standby -> is superfluous if from stbyI to stbyII
    LCU_standby_block_aot();
    //FPU stand-by: HBB is ON, chopper to rest position
    Init_MSA_aot("0","CLOSE",0.0,true,"ON");
    //HRS stand-by -> is superfluous if from stbyI to stbyII
    HRS_config_max_att_block_aot("0",["wb","wb"]);
    //WBS stand-by with laser ON
    WBS_standby_block_aot("ON");
}

//HIFI-COP-2.3-CPR-Scan1
obs HifiEng_Chopper_calibration_COP {
    int band = 1 in [1,7]; // HIFI mixer band
    int freq_index = 1 in [1,3]; //Frequency index: 2 is forbidden if sky=true
    bool sky = true; //whether or not we scan over M3 area
}{
    //General parameters in use
    int integ_time = 4;
    //Integration time PER PHASE for the slowchop measurement  
    bool shutter_used = false;
    string[] hrs_mode = ["wb1","wb1"];
    //For bands 6 and 7, use wb8
    if(band == 6 || band == 7) {
        hrs_mode = ["wb8","wb8"];
    }
    //
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Chopper_calibration_COP_proc_ops(band,sky,integ_time,shutter_used,hrs_mode,freq_index));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Chopper_calibration_COP_proc_ops(band,sky,integ_time,shutter_used,hrs_mode,freq_index);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the OTF observing mode
procedure OTFLoadChop_commanding {
    string band = "4a"; // HIFI band
    double lo_freq = 978200.0; // LO frequency in MHz
    {double,double} eff_resolution = {1.0,1.0}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4; // chunk size given by the data rates and optimum speed
    int data_time_off = 4 in [1,20]; // data dump interval on OFF
    int n_perline = 10; // Number of frequency switch cycles per line
    int n_switch_off = 3; // Number of frequency switch cycles on OFF
    int nlines_tot = 1; // Total number of lines to scan
    int n_linesperscan = 1; // Number of lines between two OFFs
    int n_loadinterval = 1; // number of nods before a load measurement
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,2,2,40,10,20,21,0]; // Timing of the observation from telescope
    int loadlength = 21; // Load duration
}{
    // Auxiliary variables
    // Create a composite readout structure for simpler handling
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // get time values from the telescope structure
    int tinitslew = telescopetimes[1];
    // Initial slew time
    int toffslew = telescopetimes[6];
    // slew dead time between points
    ////////////////////////////////////////////////////////////////////////
    // Instrument Initialization:  The instrument tuning is done as early as
    // possible, the load calibration as late as possible
    //
    // Clustering is currently not implemented in MPS - switched off here
    int clustered = 0;
    // data rates
    {int,double[]} dataparms = DataTaking(backendreadoutparms,data_time);
    double[] onrates = dataparms{1};
    dataparms = DataTaking(backendreadoutparms,data_time_off);
    double[] offrates = dataparms{1};
    int hkduration = HkReadoutTime(band,lo_freq,backendreadoutparms,false);
    int readoutdead = SlowChopReadoutDelay(band,lo_freq,backendreadoutparms);
    // Count OFFs by hand, their counter is not returned in the state array
    int ioff = 0;
    ////////////////////////////////////////////////////////////////////////
    // start state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 1) {
            // Initialization
            if(clustered != 1) {
                HIFIInitObs();
                TuneHIFI(band,lo_freq,hrs1,hrs2,wbs1{0},wbs2{0},"normal");
            }
            delay(tinitslew - (time() - startobs) - loadlength - hkduration);
            // First load measurement
            HIFISetHK("normal",false);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
        }
        if(state[0] == 4) {
            // OFF Integration
            HIFIConfigureLoadChopIntegration(data_time_off,n_switch_off,band,lo_freq,backendreadoutparms);
            HIFILoadChopOffIntegration(data_time_off,n_switch_off,band,lo_freq,offrates);
            // OFF counter
            ioff = ioff + 1;
            // Check for normal slew after OFF
            if(state[2] * state[3] < nlines_tot) {
                HIFIActiveHK("normal",toffslew);
            }
        }
        if(state[0] == 8) {
            // OTF integration
            // Check whether we come from the OFF
            if((state[2] + n_linesperscan - 1) % n_linesperscan == 0) {
                HIFIConfigureLoadChopIntegration(data_time,n_perline,band,lo_freq,backendreadoutparms);
            }
            HIFILoadChopOnIntegration(data_time,n_perline,band,lo_freq,onrates);
            // Check for normal slew towards the OFF
            if(state[2] % n_linesperscan == 0) {
                if(ioff % n_loadinterval > 0) {
                    HIFIActiveHK("normal",toffslew);
                }
            }
        }
        if(state[0] == 9) {
            // Load slew
            delay(readoutdead);
            LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
        }
        if(state[0] == 5) {
            delay(readoutdead);
            HIFICloseObs();
        }
    }
}

//HIFI-COP-X-FastImix: 21Hz oscillation investigation
obs HifiEng_Fast_Imix {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //
    //General parameters in use for Fast_Imix
    string polarization = "B";
    //mixer to be sampled: H, V or B. If B, they are done successively
    int milliSecSample = 3;
    // interval between samples
    int samplesBefore = 50;
    int samplesAfter = 1000;
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Fast_Imix_proc_ops(band,polarization,milliSecSample,samplesBefore,samplesAfter));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Fast_Imix_proc_ops(band,polarization,milliSecSample,samplesBefore,samplesAfter);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// Compute Fast Chop delay necessary for integration, procedure
procedure Apply_Fast_Chop_delay {
    int total_time = 12; //single readout time * n_wbs_start * n_wbs1
    int n_wbs_start = 1; //Number of global loop
    string band = "1a"; // HIFI band
    string backend = "both" in ["both","hrs","wbs","hrsFast","wbsFast","wbsFast2"]; //Backend in use: both, hrs, wbs, hrsFast or wbsFast
}{
    //Packet transfer time
    {double,string}[] result = ConfigurationReader("name_delays",["wbs_transfer_delay"],band,0.0);
    //
    int wbs_packet_transfer_time = iround(result[0]{0});
    //
    //In case less channels are used, one must adapt the transfer time
    if(backend == "hrs" || backend == "wbs") {
        //wbs_packet_transfer_time = 0;	//3000;
    }
    if(backend == "wbs" || backend == "both" || backend == "wbsFast" || backend == "wbsFast2") {
        //expect half backend
        //wbs_packet_transfer_time = 0;	//2000;
    }
    //
    //Compute delay: the 2 sec. contain 2x900sec for the extra HRS time, + some margin for the wbs_init of 115 msec
    int delay_fast_chop = total_time + n_wbs_start * 2 + wbs_packet_transfer_time / 1000;
    //debug_print("Fast Chop delay: " + delay_fast_chop + " sec");
    //
    //Apply delay
    delay(delay_fast_chop);
    //
}

/////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing for a
// Spectral Scan Load-chop observing mode
// 
{{int,int,int,int,int,int,bool,int,int},{int,double,double[],int[][],bool,double[],int,bool}} procedure SScanLoadChopNoRef_pre_timing {
    string band = "4a"; // HIFI band
    double lo_freq_low = 978200.0; // Lower LO frequency limit in MHz
    double lo_freq_up = 979600.0; // Upper LO frequency limit in MHz
    int redundancy = 4; // Frequency scan redundancy
    {double,double} eff_resolution = {1.1,1.1}; // Minimum and maximum goal resolution of the calibrated data in MHz
    {bool,int,double[],bool[]} hrs1 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS1 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int,double[],bool[]} hrs2 = {true,1,[-110.0,110.0,0.0,0.0],[true,true,true,true]}; // HRS2 parameters={used,resolution,frequency offsets, subbands used}
    {bool,int[][]} wbs1 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS1 parameters ={used, channel windows}
    {bool,int[][]} wbs2 = {true,[[0,2048],[0,2048],[0,2048],[0,2048]]}; // WBS2 parameters ={used, channel windows}
    int data_time = 4 in [1,20]; // data dump interval limited by the data rate/stability
    int n_chop_on = 2 in [1,900]; // number of half nu1-nu2-nu2-nu1 cycles per frequency and pointing
    int n_freq_point = 1 in [1,12]; // Number of frequency steps before pointing to second phase
    int load_interval = 1800 in [10,7200]; // load period in seconds
    bool docommands = false; // Whether instrument command loop is executed
}{
    //////////////////////////////////////////////////////////////////////
    // Create composite readout structure for backends
    {{bool,int,bool[]},{bool,int,bool[]},{bool,int[][]},{bool,int[][]}} backendreadoutparms = {{hrs1{0},hrs1{1},hrs1{3}},{hrs2{0},hrs2{1},hrs2{3}},wbs1,wbs2};
    // Get frequency grid characteristic parameters
    {int,double,double[],int[][],int,bool} fqparms = MakeFreqGrid(band,lo_freq_low,lo_freq_up,redundancy,0.0,n_freq_point);
    int groupnumber = fqparms{0};
    double reffreq = fqparms{1};
    double[] freqgrid = fqparms{2};
    int[][] grouporder = fqparms{3};
    // Process tuning level grid
    double[][] levelgrid = GetSScanLevelGrid(band,wbs1,wbs2,freqgrid,fqparms{0},grouporder);
    {bool,double[]} targets = TargetLevels(band,reffreq,levelgrid);
    bool retuning = targets{0};
    double[] targetgrid = targets{1};
    string reftarget = "";
    if(retuning) {
        reftarget = "sscan_normal";
    }
    {int,double,double[],int[][],bool,double[],int,bool} spectralparms = {fqparms{0},reffreq,freqgrid,grouporder,retuning,targetgrid,fqparms{4},fqparms{5}};
    //////////////////////////////////////////////////////////////////////
    int jitterdead = GetMaxTimeJitter(band,reffreq);
    // Integration time per frequency and pointing
    int on_inttime = 2 * n_chop_on * data_time;
    // Tuning delays
    int bigtunestep = duration(HIFIRetuneFreq(band,reffreq,reftarget));
    // Correct for variation within the band
    int tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq);
    bigtunestep = bigtunestep + tunediff;
    // A step within a group could be faster than a large step
    if(n_freq_point > 1) {
        int smallstep = duration(HIFIChangeFreq(band,reffreq));
    } else {
        smallstep = bigtunestep;
    }
    int grouptime = n_freq_point * on_inttime + (n_freq_point - 1) * smallstep;
    // Compute load integration time
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms));
    int readoutdead = SlowChopReadoutDelay(band,reffreq,backendreadoutparms);
    loadlength = loadlength + readoutdead;
    // Duration of initial set up
    // Staying at the same frequency makes no sense here. 
    // First frequency point
    double runningfreq = freqgrid[grouporder[0][0]];
    // determine exact duration only in case of full commanding
    if(docommands) {
        int initlength = duration(HIFIInitObs());
        initlength = initlength + duration(TuneHIFI(band,runningfreq,hrs1,hrs2,wbs1{0},wbs2{0},"sscan_normal"));
        // Add time for HK readout
        int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
        initlength = initlength + hkduration;
    } else {
        initlength = GetRoughInitLength(band,runningfreq,true);
    }
    initlength = initlength + loadlength;
    int initloadlength = loadlength;
    // Compare load interval with duration of the observation
    int load_spacing = CheckedLoadSpacing(load_interval - loadlength,8);
    if(load_spacing < grouptime && n_freq_point > 1) {
        SError("Load period too short for frequency group size.");
    }
    // Here we bracket each cycle by loads, this leads to a grace period
    int n_load_on = on_inttime / load_spacing;
    // In the following the definition of n_load_on is higher by 1 relative to 
    // that used in normal load-chop!
    // This determines the order of the loops
    if(n_load_on == 0) {
        int n_per_on = n_chop_on;
        bool end_load_on = false;
        // recompute load length in case of short integrations
        loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,false,eff_resolution{0},data_time,backendreadoutparms));
        loadlength = loadlength + readoutdead;
    } else {
        // grace condition
        if(double(on_inttime) > 1.2 * double(load_spacing)) {
            n_load_on = n_load_on + 1;
        }
        n_per_on = n_chop_on / n_load_on;
        if(n_per_on < 1) {
            SError("FS phase length on source too long relative to load period.");
        }
        end_load_on = true;
        on_inttime = 2 * n_per_on * n_load_on * data_time;
        // This cannot happen for n_freq_point > 1
        grouptime = on_inttime + n_load_on * loadlength;
    }
    int on_pointing = groupnumber * (grouptime + bigtunestep + loadlength) - bigtunestep - loadlength + jitterdead;
    // dangling time given by readout dead time
    int dangling = readoutdead;
    // Return all the times needed for telescope call and post_timing processing

    return {{on_inttime,on_pointing,initloadlength,load_spacing,n_per_on,n_load_on,end_load_on,initlength,dangling},spectralparms};
}

//HIFI-COP-2.3-Param-Scan: used to compute full duration
obs HifiManCmd_Parameter_Scan_MOIS {
    string warning_message = "WARNING: THIS MODE IS NOT DESIGNED TO BE SCHEDULED - ONLY HERE FOR MANUAL COMMANDING !!"; //READ THIS CAREFULLY!
    int index = 1 in [1,7]; // Test case index as of config_paramscan_COP.config
    int phase = 1 in [1,2]; //Measurement phase
    bool config_only = true; //whether we only configure ("true") or run also Stab and Tsys 
}{
    //Read corresponding band
    string tab = "config_paramscan_COP.config";
    string band = slookup(tab,"" + index,"band");
    //General parameters in use
    int integ_time = 4;
    //Integration time PER PHASE for the slowchop measurement  
    string[] hrs_mode = ["wb1","wb1"];
    //For bands 6 and 7, use wb8
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        hrs_mode = ["wb8","wb8"];
    }
    //
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing();
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(Parameter_Scan_MOIS_proc_ops(index,phase,integ_time,hrs_mode,config_only));
    // telescope command
    int[] ts = no_pointing(true,initlength,closelength,mainduration);
}{
    // Instrument commanding  - use state machine
    int[] state = [0];
    while(state[0] >= 0) {
        state = next_state();
        if(state[0] == 2) {
            // Initialization
            HIFIInitObs();
            HIFISetHK("fast",true);
        }
        if(state[0] == 3) {
            // Test execution
            Parameter_Scan_MOIS_proc_ops(index,phase,integ_time,hrs_mode,config_only);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            StopMode_block_ops();
        }
    }
}

//General LO configuration command
block HIFI_Configure_LCU_w_TMPageDump_block_fm HIFI 3917 {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double lo_freq = 500.0; //LO frequency
    int freq_nx = 0; // HL_freq_nx
    int lsu_main = 0; // HL_LSU_main
    int lsu_offset = 0; // HL_LSU_offset
    int d2_step = 1; // HL_D2_step
    double plevel_v = 0.0;
    double m1_v = 9.0;
    double m2_v = -2.0;
    double m3_v = 0.0;
    double gate1_v = -2.5;
    double gate2_v = -2.5;
    double drain1_v = 2.8;
    string curlim1_v = "1.4";
    double drain2_v = 2.6;
    string curlim2_v = "1.4";
    int macro_checksum = 0; // HL_macro_checksum
    int config_lo_delay = 6;
}{
    //Check that Vd2 is within the blue limits
    drain2_v = Check_BLUE_LIMIT_D2_proc_fm(band,lo_freq,drain2_v);
    //
    //Start_block(); 
    //
    //Execute configuration
    //Check which LO band is used
    if(band == "1a") {
        //Band 1a
        Hifi_HIFI_Conf_safe_LCU_ch1a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "1b") {
        //Band 1b
        Hifi_HIFI_Conf_safe_LCU_ch1b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2a") {
        //Band 2a
        Hifi_HIFI_Conf_safe_LCU_ch2a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "2b") {
        //Band 2b
        Hifi_HIFI_Conf_safe_LCU_ch2b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3a") {
        //Band 3a
        Hifi_HIFI_Conf_safe_LCU_ch3a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "3b") {
        //Band 3b
        Hifi_HIFI_Conf_nom_LCU_ch3b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4a") {
        //Band 4a
        Hifi_HIFI_Conf_safe_LCU_ch4a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "4b") {
        //Band 4b
        Hifi_HIFI_Conf_safe_LCU_ch4b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5a") {
        //Band 5a
        Hifi_HIFI_Conf_nom_LCU_ch5a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_nom_LCU_ch5b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_nom_LCU_ch6a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,m3_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_nom_LCU_ch6b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_nom_LCU_ch7a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_nom_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,plevel_v,m1_v,m2_v,gate1_v,gate2_v,drain1_v,curlim1_v,drain2_v,curlim2_v,macro_checksum);
    }
    //
    delay(config_lo_delay);
    //
    //Store settings into available register
    //HIFI_HL_store_tm_proc_fm();
    //
    //Additional read of TM pages
    //Normal series of 5 TCs
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM1");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM2");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM3");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_TM");
    delay(2);
    Hifi_HIFI_LCU_macro_tuning_hk("HSK_G");
    delay(2);
    //Try with 2 delays
    //Additional read of TM pages: use new TC
    Hifi_HIFI_LCU_all_tuning_hk();
    delay(2);
    //Additional read of TM pages: use new TC
    Hifi_HIFI_LCU_all_tuning_hk();
    delay(1);
}

block HKrate HIFI 901 {
    double rate = 0.25;
}{
    Start_block_no_hk_request();
    string hk_rate = "1_pkt_per_10_s";
    if(rate < 0.2) {
        hk_rate = "1_pkt_per_10_s";
    }
    if(rate >= 0.2 && rate < 0.25) {
        hk_rate = "1_pkt_per_5_s";
    }
    if(rate >= 0.25 && rate < 0.33) {
        hk_rate = "1_pkt_per_4_s";
    }
    if(rate >= 0.33 && rate < 1.0) {
        hk_rate = "1_pkt_per_3_s";
    }
    if(rate >= 1.0) {
        hk_rate = "1_pkt_per_s";
    }
    Hifi_HIFI_Housekeeping_on(hk_rate,"ON","ON","ON","ON","ON","ON");
    delay(1);
}

//HIFI HK control, procedure
procedure Switch_HK_proc_ops {
    string hk_FCU = "ON" in ["ON","OFF"]; //Status of FCU HK
    string hk_LCU = "ON" in ["ON","OFF"]; //Status of LCU HK
    string hk_WBSV = "ON" in ["ON","OFF"]; //Status of WBSV HK
    string hk_WBSH = "ON" in ["ON","OFF"]; //Status of WBSH HK
    string hk_HRSV = "ON" in ["ON","OFF"]; //Status of HRSV HK
    string hk_HRSH = "ON" in ["ON","OFF"]; //Status of HRSH HK
}{
    //Get applicable HK rate
    {double,string}[] result_d = ConfigurationReader("name_delays",["hk_rate"],"0",0.0);
    string hk_rate = result_d[0]{1};
    Hifi_HIFI_Housekeeping_on(hk_rate,hk_FCU,hk_LCU,hk_WBSV,hk_WBSH,hk_HRSV,hk_HRSH);
    delay(1);
}

// Routine to check whether loadlength is short compared to
// load interval, so that loadspacing is reasonably long
int procedure CheckedLoadSpacing {
    int load_spacing = 100; // time interval between load measurements
    int minspacing = 8; // minimum interval
}{
    if(load_spacing < minspacing) {
        IError("Required load calibration time too long. " + "Increase lower goal resolution limit.");
    }

    return load_spacing;
}

//  LCU2a configuration into SAFE mode, procedure
procedure LCU2a_config_safe_proc_fm {
    string band = "2a"; // HIFI band
    double lo_freq = 700.0 in [647.0,710.0]; //LO frequency
}{
    error("This module is obsolete: use LCU_config_nominal_proc_fm instead");
}

