// 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
    int tline = telescopetimes[4];
    // Time in line
    // The telescope slew can be a bit further than requested
    int line_inttime = n_pp * data_time;
    {int,int} otfline = OtfTelescopeLine(line_inttime,tline);
    int line_startdelay = otfline{1};
    ////////////////////////////////////////////////////////////////////////
    // 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
            delay(line_startdelay);
            // 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};
}

// 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("Noise values are given at this frequency for the single-sideband" + " deconvolution product, and the double-sideband pipeline " + "products for individual LO settings on a " + "polarization-averaged, " + "single-sideband, main beam temperature scale of a " + fwhm + "'' beam with a main beam efficiency of " + eta_mb * 100.0 + "%.", 1);
    } else {
        message("Noise values are given on a polarization-averaged," + " single-sideband, main beam temperature scale of a " + fwhm + "'' beam with a main beam efficiency of " + eta_mb * 100.0 + "%.", 1);
    }
    message("</strong></p>");
}

//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
}{
    //
}

/////////////////////////////////////////////////////////////////
// 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};
}

/////////////////////////////////////////////////////////////////
// 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;
}

// Read addresses and get checksum for a given band
// Returns:
//   - the array of address_start, address_length
//   - the full checksum of a given band
//   - the full length of all concatenated address areas
//
{{int,int}[],int,int} procedure LcuGetTableAddress_ops {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    string tab = "LcuAddressTable_R.config";
    int bandnb = ilookup(tab,band,"bnum");
    {int,int}[] pairs = [];
    int total_length = 0;
    int total = 12;
    //Get inputs for band 1a - loop on location types
    for(int line = 1 .. total) {
        string add_name_S = "a" + line + "S";
        //Start address in Hex
        string add_name_L = "a" + line + "L";
        //Length in byte
        int add_S_1a = ilookup(tab,"1a",add_name_S);
        int add_L_1a = ilookup(tab,"1a",add_name_L);
        int add_S_band = add_S_1a + (bandnb - 1) * add_L_1a;
        int add_L_band = add_L_1a;
        pairs[line - 1] = {add_S_band,add_L_band};
        //Full length of all concatenated address areas
        total_length = total_length + add_L_band;
    }
    //Complement with zeroes until getting to 48 pairs
    int hifi_NStep = 48;
    for(int line2 = total + 1 .. hifi_NStep) {
        add_S_band = 0;
        add_L_band = 0;
        pairs[line2 - 1] = {add_S_band,add_L_band};
    }
    //Get checksum
    int crc = ilookup(tab,band,"crc");

    return {pairs,crc,total_length};
}

// Procedure to compute the LO settling delay for a particular frequency
//
int procedure LOSettlingTime {
    string band = "4a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    double rest_lofreq = 978.2; // LO frequency in GHz ! (David's units!)
    bool usesVectorScan = false; // whether to make room for the vector scan 
    bool extradelay = true; //whether extra settling time is needed after chain is configured
}{
    // check for needed overhead factor
    if(usesVectorScan) {
        double tune_range_factor = 1.05;
    } else {
        tune_range_factor = 1.0;
    }
    // Get all parameters needed to compute config_lo_delay in Configure_LCU
    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";
    }
    //
    // 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);
    {double,string}[] result = ConfigurationReader(name_configlcutune,["drain2_v"],band,rest_lofreq / maxredshift);
    double drain2_lowredshift = min(result[0]{0} * tune_range_factor,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} * tune_range_factor,drain2_bluemax_highredshift);
    //
    // Safe value
    // (LO frequency must be in GHz here in contrast to other cal files.)
    double[] cresult = CalibrationReader("name_lcu_safe_values",["d2_v"],band,rest_lofreq);
    double drain2_safe = cresult[0];
    //
    // 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});
    //
    //Add extra time if needed
    if(extradelay) {
        cresult = CalibrationReader("tunetime",["extra_tune_delay"],band,rest_lofreq);
        config_lo_delay = config_lo_delay + iceil(cresult[0]);
    }
    // return result

    return config_lo_delay;
}

//Set LOU to dissipative, block
block Set_LO_Dissipative_block_aot HIFI 6627 {
}{
    mois_step("Switch to dissipative mode");
    {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_dissipative($BBID);
    delay(set_to_nominal_delay);
    //
}

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);
    // 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;
    }
    bool isOffAtPoint = false;
    ////////////////////////////////////////////////////////////////////////
    // 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;
            iphase = iphase + 1;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            // Check whether we are in a cross mode using computed OFF
            isOffAtPoint = iscross && inod % 2 == 0;
            // Configure measurement
            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) {
                if(isOffAtPoint) {
                    HIFIFastHalfChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                } else {
                    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
            if(isOffAtPoint) {
                HIFIFastHalfChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            } else {
                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(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},load_datatime,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
            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(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},load_datatime,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},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}};
}

//////////////////////////////////////////////////////////////////////
// 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
    double avgainfac = 0.5 / gssb[0] + 0.5 / gssb[1];
    double rescalefac = sqrt(double(nfreq)) * avgainfac;
    if(dsb) {
        // Combine both sidebands
        // In full spectral scans we have only a combined noise temperature for 
        // both sidebands
        double decnoise_lores = dsbnoise_lores / sqrt(gssb[0] * gssb[0] + gssb[1] * gssb[1]);
        double decnoise_hires = dsbnoise_hires / sqrt(gssb[0] * gssb[0] + gssb[1] * gssb[1]);
        double indnoise_lores = dsbnoise_lores * rescalefac;
        double indnoise_hires = dsbnoise_hires * rescalefac;
    } else {
        // Get single sideband noise equivalent
        decnoise_lores = dsbnoise_lores * avgainfac;
        decnoise_hires = dsbnoise_hires * avgainfac;
        indnoise_lores = dsbnoise_lores * rescalefac;
        indnoise_hires = dsbnoise_hires * rescalefac;
    }
    // In spectral scans we have only a combined noise temperature for both
    // sidebands, so that the USB/LSB separation is not used

    return {decnoise_lores,decnoise_hires,indnoise_lores,indnoise_hires,noiseratio};
}

// 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;
}

// 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]);
}

// procedure called to get the WBS lasers switched on
procedure HifiSetFromDissipative_I_IntoDissipative_II {
    string band_dissipate = "4a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //Temporarily, HEBs cannot be used - needs new MIB
    if(band_dissipate == "6a" || band_dissipate == "6b" || band_dissipate == "7a" || band_dissipate == "7b") {
        //error("HEB bands cannot yet be used in dissipative mode");
    }
    // 
    //WBS stand-by with laser ON
    WBS_standby_block_aot("ON");
    //Warm-up LOU with next band to be used
    if(band_dissipate == "0") {
        //Do nothing as one should already be in band0
    } else {
        //Clear potential failure mode
        Set_LO_Nominal_block_aot();
        //Heater will remain at 4V
        LCU_config_dissipative_w_D2_proc_aot(band_dissipate);
    }
    //
}

/////////////////////////////////////////////////////////////////
// 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});
    ChopMessages(true,data_time,n_int_on);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

////////////////////////////////////
// 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});
    ChopMessages(false,data_time,n_switch_on);
    RasterSizeMessages({0.0,0.0},stepsize,2,npoints,true);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

////////////////////////////////////////////////////////////////////////////
// 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
    int tline = telescopetimes[4];
    // Time in line
    // The telescope slew can be a bit further than requested
    int line_inttime = 2 * n_perline * data_time;
    {int,int} otfline = OtfTelescopeLine(line_inttime,tline);
    int line_startdelay = otfline{1};
    ////////////////////////////////////////////////////////////////////////
    // 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
            delay(line_startdelay);
            // 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();
        }
    }
}

//Transition mode from normal to dissipative2
procedure HifiSetFromNormal_IntoDissipative_II {
    string band_dissipate = "4a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //Temporarily, HEBs cannot be used - needs new MIB
    if(band_dissipate == "6a" || band_dissipate == "6b" || band_dissipate == "7a" || band_dissipate == "7b") {
        //error("HEB bands cannot yet be used in dissipative mode");
    }
    //
    if(band_dissipate == "0") {
        //Clear potential failure mode
        Set_LO_Nominal_block_aot();
        //
        LCU_switch_off_block_aot();
        //Will put heaters to 6V
        Set_LO_Dissipative_block_aot();
    } else {
        //Clear potential failure mode
        Set_LO_Nominal_block_aot();
        //Heater will remain at 4V
        LCU_config_dissipative_w_D2_proc_aot(band_dissipate);
    }
    //
    //FPU stand-by: HBB is ON, chopper to rest position
    Init_MSA_aot("0","CLOSE",0.0,true,"ON");
    //HRS stand-by
    HRS_config_max_att_block_aot("0",["wb","wb"]);
    //WBS stand-by with laser ON
    WBS_standby_block_aot("ON");
    //Enable checksum computation - moved to transition to diss1 (HIFI-3578)
    //Enable_CRC_FDIR_block_ops();
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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);
    // Insert a Noop because previous command could have been issued in second bus slot
    Hifi_HIFI_noop();
    // 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);
}

/////////////////////////////////////////////////////////////////
// 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;
}

////////////////////////////////////
// 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};
}

////////////////////////////////////
// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 support conditional LCU CRC computation
// together with standard HK configuration - HIFI-3415
procedure HIFILCUChecksumAndSetHKCloseObs {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    bool alltables = true; //check all tables+unused (true), or only one band table (false)
    string speed = "normal" in ["fast","normal","slow"]; // Select HK rate
    bool active = false; // Whether to actively query the spectrometers
}{
    HIFISetHK(speed,active);
    LcuChecksumRecalcCloseObs_aot(band,alltables);
}

//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);
    // tss not relevant for ncycles=1, scansize=1
    if(scansize != 1 || n_cycles != 1) {
        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(n_loadinterval > 1 && (dangling_period + n_loadinterval) * 2 * scan_time > load_interval - loadlength + nodtime) {
            n_loadinterval = n_loadinterval - 1;
            dangling_period = n_cycles % n_loadinterval;
        }
        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};
}

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

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

/////////////////////////////////////////////////////////////////
// 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.");
    }
}

////////////////////////////////////////////////////
// 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);
}

// OBS SFT, block
procedure OBS_SEU_check_aot {
    string memory_area = "PM_LOW" in ["PM_LOW","PM_HIGH","DM","EEPROM1","EEPROM2","BSW","ALL"];
}{
    if(memory_area == "ALL") {
        //De-activate S/S HK collection during the checks
        Hifi_HIFI_Housekeeping_off();
        delay(1);
    }
    //Parameters for PM-low: this is for OBS6.4.1
    int check_start = ilookup("config_icu_memory.config","PM_LOW","start");
    int check_end = ilookup("config_icu_memory.config","PM_LOW","end_or_length");
    int check_crc = ilookup("config_icu_memory.config","PM_LOW","crc");
    //PM_LOW check
    if(memory_area == "PM_LOW" || memory_area == "ALL") {
        mois_spacon("In the following TC, parameters HP231197, HP232197 and HP233197 should be treated as formal parameters");
        Hifi_HIFI_check_PM_memory(check_start,check_end,check_crc);
        delay(3);
        mois_tmcheck("Verify that no 1,8 has been generated. Otherwise, please inform the HIFI ICC.");
    }
    //PM_HIGH check
    if(memory_area == "PM_HIGH" || memory_area == "ALL") {
        check_start = check_start + 0x3ffff;
        check_end = check_end + 0x3ffff;
        mois_spacon("In the following TC, parameters HP231197, HP232197 and HP233197 should be treated as formal parameters");
        Hifi_HIFI_check_PM_memory(check_start,check_end,check_crc);
        delay(3);
        mois_tmcheck("Verify that no 1,8 has been generated. Otherwise, please inform the HIFI ICC.");
    }
    //PROM copy into PM (BSW) check
    if(memory_area == "BSW" || memory_area == "ALL") {
        check_start = ilookup("config_icu_memory.config","BSW","start");
        check_end = ilookup("config_icu_memory.config","BSW","end_or_length");
        check_crc = ilookup("config_icu_memory.config","BSW","crc");
        mois_spacon("In the following TC, parameters HP231197, HP232197 and HP233197 should be treated as formal parameters");
        Hifi_HIFI_check_PM_memory(check_start,check_end,check_crc);
        delay(1);
        mois_tmcheck("Verify that no 1,8 has been generated. Otherwise, please inform the HIFI ICC.");
    }
    //DM check
    if(memory_area == "DM" || memory_area == "ALL") {
        //There are three segments to consider here
        check_start = ilookup("config_icu_memory.config","DM1","start");
        int check_length = ilookup("config_icu_memory.config","DM1","end_or_length");
        mois_spacon("In the following TCs, parameters HP003197 and HP004197 should be treated as formal parameters");
        Hifi_HIFI_check_memory("DM",check_start,check_length);
        delay(1);
        //
        check_start = ilookup("config_icu_memory.config","DM2","start");
        check_length = ilookup("config_icu_memory.config","DM2","end_or_length");
        Hifi_HIFI_check_memory("DM",check_start,check_length);
        delay(1);
        //
        check_start = ilookup("config_icu_memory.config","DM3","start");
        check_length = ilookup("config_icu_memory.config","DM3","end_or_length");
        Hifi_HIFI_check_memory("DM",check_start,check_length);
        delay(1);
        //
    }
    //EEPROM1 check: done in two chunks due to length limit to 16 bits
    if(memory_area == "EEPROM1" || memory_area == "ALL") {
        check_start = ilookup("config_icu_memory.config","EEPROM1_1","start");
        check_length = ilookup("config_icu_memory.config","EEPROM1_1","end_or_length");
        mois_spacon("In the following TC, parameters HP003197 and HP004197 should be treated as formal parameters");
        Hifi_HIFI_check_memory("EEPROM",check_start,check_length);
        delay(1);
        check_start = ilookup("config_icu_memory.config","EEPROM1_2","start");
        check_length = ilookup("config_icu_memory.config","EEPROM1_2","end_or_length");
        mois_spacon("In the following TC, parameters HP003197 and HP004197 should be treated as formal parameters");
        Hifi_HIFI_check_memory("EEPROM",check_start,check_length);
        delay(1);
    }
    //EEPROM2 check: done in two chunks due to length limit to 16 bits
    if(memory_area == "EEPROM2" || memory_area == "ALL") {
        check_start = ilookup("config_icu_memory.config","EEPROM2_1","start");
        check_length = ilookup("config_icu_memory.config","EEPROM2_1","end_or_length");
        mois_spacon("In the following TC, parameters HP003197 and HP004197 should be treated as formal parameters");
        Hifi_HIFI_check_memory("EEPROM",check_start,check_length);
        delay(1);
        check_start = ilookup("config_icu_memory.config","EEPROM2_2","start");
        check_length = ilookup("config_icu_memory.config","EEPROM2_2","end_or_length");
        mois_spacon("In the following TC, parameters HP003197 and HP004197 should be treated as formal parameters");
        Hifi_HIFI_check_memory("EEPROM",check_start,check_length);
        delay(1);
    }
    //
    if(memory_area == "ALL") {
        //Re-activate S/S HK collection during the checks
        Hifi_HIFI_Housekeeping_on("1_pkt_per_s","ON","ON","ON","ON","ON","ON");
    }
}

////////////////////////////////////////////////////////////////////////////
// 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();
        }
    }
}

// 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_on = 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_on = wshort * tdeadother_on + 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};
    // treat integration times of other frequencies as dead time
    double tdeadother_off = double(data_time_off * 2 * n_chop_off);
    // 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(grouplen * n_cycles);
        wshort = double(n_cycles * grouplen - numlong_off) / double(grouplen * n_cycles);
        tdeadint_off = wlong * tdeadlong + wshort * tdeadint_off;
        tphaseint_off = (wlong * tinst{0} + wshort * tphaseint_off) / (2.0 * avnumchop_off);
        tdeadother_off = wshort * tdeadother_off + double(data_time_off * 2 * n_long_off) * wlong;
    } 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(grouplen * 2 * data_time_off) * avnumchop_off;
    double tdead_tot = tdead + tdeadint_on + tdeadint_off;
    // Add integration times of other frequencies as dead time
    tdead_tot = tdead_tot + double(grouplen - 1) * (tdeadother_on + tdeadother_off);
    // 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 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();
        }
    }
}

/////////////////////////////////////////////////////////////////
// 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
    // Get appropriate settings for selected HIFI band
    double[] x = CalibrationReader("backendselect",["window1_lo","window1_up","window2_lo","window2_up","window3_lo","window3_up","window4_lo","window4_up"],band,0.0);
    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])]];
    {bool,int[][]} wbs1 = {wbs1_used,stdWbsWindows};
    {bool,int[][]} wbs2 = {wbs2_used,stdWbsWindows};
    // 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};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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,"fs",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,true);
    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));
        tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq,false);
        smallstep = smallstep + 2 * tunediff;
    } 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};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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();
        }
    }
}

// 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);
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

//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;
}

//Procedure to calculate individual LCU memory segments
procedure LcuChecksumRecalcSegmented_aot {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string code_category = "Safe" in ["Safe","Critical","Table","Table_all","Unused"]; //Safe, Critical, Table, Unused or Table_all 
    string hifi_HIF_block_when_nok = "NO" in ["YES","NO"]; // HIF_block_when_nok
}{
    //Band 0 can be chosen in transition to dissipative_II
    //If it is selected and test is on table, only the delay is kept
    if(band == "0" && code_category == "Table") {
        delay(2);
    } else {
        //If we are in band 0, band number has to be changed as place-holder
        if(band == "0") {
            band = "1a";
        }
        //
        //Criticality keyword
        string hifi_HIF_lcu_critical = "Safe";
        if(code_category == "Table") {
            hifi_HIF_lcu_critical = "Table";
        }
        if(code_category == "Critical") {
            hifi_HIF_lcu_critical = "Critical";
        }
        //
        {int,int}[] addresses = [];
        int hifi_Nsteps = 48;
        //Fix number of entries in addresses
        //Get tupple of addresses and checksum
        if(code_category == "Table") {
            {{int,int}[],int,int} add_crc = LcuGetTableAddress_ops(band);
            addresses = add_crc{0};
            int crc_total = add_crc{1};
            int length_total = add_crc{2};
        }
        if(code_category == "Safe" || code_category == "Critical" || code_category == "Unused") {
            add_crc = LcuGetCodeAddress_ops(code_category);
            addresses = add_crc{0};
            crc_total = add_crc{1};
            length_total = add_crc{2};
        }
        if(code_category == "Table_all") {
            //Get start address, and length for one band
            add_crc = LcuGetTableAddress_ops("1a");
            int address_start = add_crc{0}[0]{0};
            crc_total = add_crc{1};
            length_total = 14 * add_crc{2};
            addresses = add_crc{0};
            addresses[0] = {address_start,length_total};
            for(int j = 1 .. hifi_Nsteps - 1) {
                addresses[j] = {0,0};
            }
            //Loop on bands for individual checksums
            string[] band_array = ["1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"];
            for(int i = 0 .. 12) {
                add_crc = LcuGetTableAddress_ops(band_array[i]);
                crc_total = crc_total + add_crc{1};
            }
            //Wrap-around CRC
            crc_total = crc_total % (0xffff + 1);
            //
        }
        //Send TC to ICU
        Hifi_HIFI_check_LCU_memparts($BBID,hifi_HIF_lcu_critical,band,hifi_HIF_block_when_nok,crc_total,hifi_Nsteps,addresses);
        //Compute total delay: proportional to size to compute
        double crc_speed = 66000.0;
        //in byte/sec 
        int checksum_total_delay = iceil(double(length_total) / crc_speed) + 1;
        delay(checksum_total_delay);
        //
    }
}

// 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;
}

//////////////////////////////////////////////////////////////////////
// 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);
    // Combined sideband scaling
    double[] gssb = InterpolateGssb(band,reffreq);
    double avgainfac = 0.5 / gssb[0] + 0.5 / gssb[1];
    double rescalefac = gssb[1] * avgainfac;
    // Correct for multiple frequencies
    double multiplier = sqrt(1.0 / double(nfreq));
    noisevalues{0} = noisevalues{0} * gssb[0] * multiplier;
    noisevalues{1} = noisevalues{1} * gssb[0] * 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 decnoise_lores = noisevalues{0} / sqrt(gssb[0] * gssb[0] + gssb[1] * gssb[1]);
        double decnoise_hires = noisevalues{1} / sqrt(gssb[0] * gssb[0] + gssb[1] * gssb[1]);
        double indnoise_lores = noisevalues{2} * rescalefac;
        double indnoise_hires = noisevalues{3} * rescalefac;
    } else {
        // Get single sideband noise equivalent
        decnoise_lores = noisevalues{0} * avgainfac;
        decnoise_hires = noisevalues{1} * avgainfac;
        indnoise_lores = noisevalues{2} * rescalefac;
        indnoise_hires = noisevalues{3} * rescalefac;
    }
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {decnoise_lores,decnoise_hires,indnoise_lores,indnoise_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});
}

////////////////////////////////////////////////////////////////////////////
// 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);
    // 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;
    int ihold = 0;
    // Do I have to make loads in short nods and subsequent holds?
    if(iscross) {
        bool holdforload = n_pointsperscan > 1;
        int phaseshift = 0;
    } else {
        holdforload = n_pointsperscan == 1 && n_loadinterval > n_cycles;
        phaseshift = 1;
    }
    bool isOffAtPoint = false;
    bool isLastPhase = false;
    ////////////////////////////////////////////////////////////////////////
    // 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;
            iphase = iphase + 1;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            // Sanity check
            if(runintostate && iscross) {
                CError("Ongoing integration while arriving at ON nodding position.");
            }
            // Check whether we are in a cross mode using computed OFF
            isOffAtPoint = iscross && holdforload && inod % 2 == 1;
            // Configure measurement
            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) {
                if(isOffAtPoint) {
                    HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                } else {
                    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
            if(isOffAtPoint) {
                HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            } else {
                HIFIFastChopOnIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            }
            // Final point before nod
            // Dirty trick to find out whether we are at the very last point
            isLastPhase = telescopetimes[0] + tinitslew - (time() - startobs) < data_time * n_seq;
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == 1) {
                inod = inod + 1;
            }
            // 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 == phaseshift) {
                ihold = ihold + 1;
                if(holdforload && ihold % n_loadinterval == 0 && n_load == 0 && !isLastPhase) {
                    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 measurement between two A-A or B-B phases if required
                // Time partially included in pointing
                if(n_load > 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    // Run into final hold for very last point
                    if(isLastPhase) {
                        runintostate = true;
                    }
                }
            }
            // Update phase counter
            iphase = iphase + 1;
        }
        // Second pointing phase
        if(state[0] == 7) {
            // second nod position
            // Sanity check
            if(runintostate && iscross) {
                CError("Ongoing integration while arriving at OFF nodding 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);
            // Final point before nod
            // Dirty trick to find out whether we are at the very last point
            isLastPhase = telescopetimes[0] + tinitslew - (time() - startobs) < data_time * n_seq;
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == 1) {
                inod = inod + 1;
            }
            // Special treatment for all cases where load has to be replaced by hold:
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == phaseshift) {
                ihold = ihold + 1;
                if(holdforload && ihold % n_loadinterval == 0 && n_load == 0 && !isLastPhase) {
                    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 measurement between two A-A or B-B phases if required
                // Time partially included in pointing
                if(n_load > 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
                    // Run into final hold for very last point
                    if(isLastPhase) {
                        runintostate = true;
                    }
                }
            }
            // Update phase counter
            iphase = iphase + 1;
        }
        // Load nod
        if(state[0] == 9) {
            // Load nod
            // Sanity check
            if(runintostate) {
                CError("Ongoing integration while starting load calibration slew.");
            }
            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) {
            if(!runintostate) {
                delay(readoutdead);
            }
            if(final_load) {
                // Perform final load measurement 
                LoadMeasurement(band,lo_freq,eff_resolution{0},load_datatime,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

////////////////////////////////////////////////////////////////////////////
// Procedure to generate the instrument commands for the observing mode
procedure EngSScanDBS_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}
    double[] freqgrid = [978053.7,978301.8,978381.1]; // Table of frequency points
    bool retunediplexer = false; // need for diplexer retuning
    bool retunelo = false; // whether to retune LO Vd2 with freq
    int data_time = 4; // chunk size
    int n_chop = 1; // Normal number of chop cycles per frequency and pointing
    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 shiftlength = 10; // Shift of the loop start relative to the pointing
    int startobs = 0; // Actual starting time of observation
    int[] telescopetimes = [300,180,20,1,21,0]; // Timing of the observation from telescope
}{
    // 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
    // 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 tune duration for initial load measurement
    int bigtunestep = duration(HIFIChangeLO(band,freqgrid[0],reffreq,retunediplexer,retunelo));
    int n_loadinterval = n_cycles;
    // 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_freq = 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:  
            // Start with setup at reference frequency, go to grid in the next step
            //
            HIFIInitObs();
            TuneHIFI(band,reffreq,hrs1,hrs2,wbs1{0},wbs2{0},"sscan_normal");
            // First load measurement
            HIFISetHK("normal",false);
            SScanLoadMeasurement(band,reffreq,reffreq,true,eff_resolution{0},data_time,backendreadoutparms);
            delay(tinitslew - (time() - startobs) - bigtunestep + shiftlength - hkduration);
            //
            // Now switch to the actual frequency grid to be measured
            double runningfreq = freqgrid[i_freq];
            HIFIChangeLO(band,runningfreq,reffreq,retunediplexer,retunelo);
            runintostate = true;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            // state counters
            runintostate = false;
            i_phase = (state[2] + 1) % 2;
            // intermediate nod cycles without retuning
            // (Check for match with first or last cycle index)
            if(n_cycles > 1 && state[2] % n_cycles != state[2] % 2) {
                delay(shiftlength);
            }
            // Actual integration
            HIFIConfigureSlowChopIntegration(data_time,n_chop,band,reffreq,backendreadoutparms);
            HIFISlowChopOnIntegration(data_time,n_chop,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_freq = i_freq + 1;
                    runningfreq = freqgrid[i_freq];
                    HIFIChangeLO(band,runningfreq,reffreq,retunediplexer,retunelo);
                    runintostate = true;
                }
            }
            // Active Backend HK if we have a nod slew without calibration
            if(i_phase == 0 && state[2] % n_loadinterval > 0) {
                HIFIActiveHK("normal",tnodslew);
            }
        }
        if(state[0] == 7) {
            // Second nodding position
            // state counters
            runintostate = false;
            i_phase = state[2] % 2;
            // intermediate nod cycles without retuning
            if(n_cycles > 1 && state[2] % n_cycles != (state[2] + 1) % 2) {
                delay(shiftlength);
            }
            // Actual integration
            HIFIConfigureSlowChopIntegration(data_time,n_chop,band,reffreq,backendreadoutparms);
            HIFISlowChopOffIntegration(data_time,n_chop,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_freq = i_freq + 1;
                    runningfreq = freqgrid[i_freq];
                    HIFIChangeLO(band,runningfreq,reffreq,retunediplexer,retunelo);
                    runintostate = true;
                }
            }
            // Active Backend HK if we have a nod slew without calibration
            if(i_phase == 0 && state[2] % n_loadinterval > 0) {
                HIFIActiveHK("normal",tnodslew);
            }
        }
        if(state[0] == 9) {
            // Load nod
            delay(readoutdead);
            SScanLoadMeasurement(band,runningfreq,reffreq,false,eff_resolution{0},data_time,backendreadoutparms);
            runintostate = false;
        }
        if(state[0] == 5) {
            // The instrument stops shiftlength before the telescope
            // but I have to wait to close the observation
            HIFICloseObs();
        }
    }
}

//General LO configuration command
block HIFI_Configure_LCU_dissipative_block_aot HIFI 6717 {
    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_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_safe_LCU_ch5a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "5b") {
        //Band 5b
        Hifi_HIFI_Conf_safe_LCU_ch5b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6a") {
        //Band 6a
        Hifi_HIFI_Conf_safe_LCU_ch6a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "6b") {
        //Band 6b
        Hifi_HIFI_Conf_safe_LCU_ch6b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7a") {
        //Band 7a
        Hifi_HIFI_Conf_safe_LCU_ch7a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    if(band == "7b") {
        //Band 7b
        Hifi_HIFI_Conf_safe_LCU_ch7b($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
    }
    //
    delay(config_lo_delay);
    //
    //Read TM pages and clear error flags
    LCU_Read_TM_pages_proc_aot();
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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,"lchop");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // 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);
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    int load_datatime = iceil(retvalues[0]{1});
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,effResolution{0},load_datatime,backendreadoutparms));
    int perfreqtime = 2 * load_datatime + tunedelay;
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    retvalues[1] = {"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)};

    return retvalues;
}

////////////////////////////////////////////////////////////////////////
// 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;
}

/////////////////////////////////////////////////////////////////
// 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();
        }
    }
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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,imin(data_time,data_time_off));
    {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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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 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;
}

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

// 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});
    ChopMessages(false,data_time,n_switch_on);
    RasterSizeMessages(lineDistance,stepsize,nlines,npoints,false);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

/////////////////////////////////////////////////////////////////
// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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;
}

//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}[1] / 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);
    //
}

/////////////////////////////////////////////////////////////////
// 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;
}

////////////////////////////////////
// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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,imin(data_time,data_time_off));
    {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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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};
}

// 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);
}

// 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);
}

//////////////////////////////////////////////////////////////////////
// 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};
}

// 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 telinit = telescopetimes[1];
    // Initial slew time
    int tend = telescopetimes[2];
    // Final deceleration time
    totaltime = totaltime + tend + telinit - initlength;
    // 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();
            HIFILCUChecksumAndSetHK(band,"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
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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});
    ChopMessages(true,data_time,n_int_on);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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,"dbs",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};
}

//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(); 
    //Disable checksum FDIR - HIFI-3120
    Disable_CRC_FDIR_block_ops();
}

// 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;
}

///////////////////////////////////////////////////////////////////////////////
// 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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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});
    ChopMessages(false,data_time,n_switch_on);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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};
}

//Transition mode from standby1 to dissipative1
procedure HifiSetFromStandby_I_IntoDissipative_I {
}{
    //
    //Clear potential failure mode
    Set_LO_Nominal_block_aot();
    //
    LCU_switch_off_block_aot();
    //Will put heaters to 6V
    Set_LO_Dissipative_block_aot();
    //
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// 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,true);
    //Magnet tuning: use either HRS or WBS, not for bands 1,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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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,imin(data_time,data_time_off));
    {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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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) {
            i_phase = (state[2] + 1) % 2;
            // 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);
            }
            // Other frequencies
            // Reset group counter
            i_group = 1;
            while(i_group <= grouplen - 1) {
                // retune
                runningfreq = freqgrid[grouporder[i_phase][i_group] + i_freqcycles * grouplen];
                HIFIChangeFreqFsw(band,runningfreq,freq_throw);
                if(i_group == 1) {
                    if(isinvalid || islong) {
                        HIFIConfigureFSwitchIntegration(data_time_off,n_per_off,band,reffreq,backendreadoutparms);
                        islong = false;
                        isinvalid = false;
                    }
                }
                HIFIFSwitchOnIntegration(data_time_off,n_per_off,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 && 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;
            while(i_group <= grouplen - 1) {
                // retune
                runningfreq = freqgrid[grouporder[i_phase][i_group] + i_freqcycles * grouplen];
                HIFIChangeFreqFsw(band,runningfreq,freq_throw);
                if(i_group == 1) {
                    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);
                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];
}

// 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.");
    }
}

// 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};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

// Read addresses and get checksum for a given code category
// Returns:
//   - the array of address_start, address_length
//   - the full checksum of all concatenated address areas
//   - the full length of all concatenated address areas
//
{{int,int}[],int,int} procedure LcuGetCodeAddress_ops {
    string code_category = "Safe" in ["Safe","Critical","Unused"]; //safe, critical or unused
}{
    string tab = "LcuAddressCode" + code_category + "_R.config";
    {int,int}[] pairs = [];
    int total_length = 0;
    int total_crc = 0;
    int total = table_size(tab);
    //Get inputs for band 1a - loop on location types
    for(int line = 1 .. total) {
        int add_S = ilookup(tab,"" + line,"a1S");
        int add_L = ilookup(tab,"" + line,"a1L");
        pairs[line - 1] = {add_S,add_L};
        total_crc = total_crc + ilookup(tab,"" + line,"crc");
        total_length = total_length + add_L;
    }
    //Complement with zeroes until getting to 48 pairs
    int hifi_NStep = 48;
    for(int line2 = total + 1 .. hifi_NStep) {
        add_S = 0;
        add_L = 0;
        pairs[line2 - 1] = {add_S,add_L};
    }
    //Wrap-around CRC
    total_crc = total_crc % (0xffff + 1);
    //

    return {pairs,total_crc,total_length};
}

// 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);
    }
}

/////////////////////////////////////////////////////////////////
// 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,"dbs");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // 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;
    }
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,effResolution{0},data_time_guess,backendreadoutparms));
    int perfreqtime = 2 * (2 * data_time_guess * n_switch_on_guess + tunedelay);
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_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;
}

// 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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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,"lo_frequency");
    // 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};
}

// 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;
}

///////////////////////////////////////////////////////
// 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);
}

//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;
}

////////////////////////////////////
// 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;
}

// 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;
    string modeName = "freq" in ["freq","fs-freq","load-freq"]; // reference scheme to use
}{
    // 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;
    // translate modeName names ["freq",fs-freq",load-freq"] into 
    // refmode names ["dbs","fs","lchop"]
    if(modeName == "fs-freq") {
        string refmode = "fs";
    } else {
        if(modeName == "load-freq") {
            refmode = "lchop";
        } else {
            refmode = "dbs";
        }
    }
    // Call CUS routine
    int grouplen = GetSpectralScanGroupLength(band,lo_freq,lo_freq_up,redundancy,refmode);

    return grouplen;
}

// Recalculate and verify LCU memory checksum at end of obsid or OD
block LcuChecksumRecalcCloseObs_aot HIFI 7906 {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    bool alltables = true; //check all tables+unused (true), or only one band table (false)
}{
    if(alltables) {
        //Check all tables
        string block_IF_NOK = "NO";
        LcuChecksumRecalcSegmented_aot(band,"Table_all",block_IF_NOK);
        //Check un-used area
        block_IF_NOK = "NO";
        LcuChecksumRecalcSegmented_aot(band,"Unused",block_IF_NOK);
        //ICU all memory checks - HIFI-3662 - Activated in cycle 26
        OBS_SEU_check_aot("ALL");
    } else {
        //Check table only
        block_IF_NOK = "NO";
        LcuChecksumRecalcSegmented_aot(band,"Table",block_IF_NOK);
    }
}

// Sort array, bubblesort, maximum will be first element
double[] procedure DSort {
    double[] x = [0.0]; // Input array
    int nlen = 1; // Array length (keep dan gling numbers untouched)
}{
    double tmpstore = 0.0;
    // double loop
    for(int i = 0 .. nlen - 2) {
        for(int j = 1 .. nlen - 1 - i) {
            if(x[j] > x[j - 1]) {
                tmpstore = x[j];
                x[j] = x[j - 1];
                x[j - 1] = tmpstore;
            }
        }
    }

    return x;
}

/////////////////////////////////////////////////////////////////
// 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}};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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,"dbs",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});
    ChopMessages(false,data_time,n_switch_on);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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);
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

//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;
}

////////////////////////////////////////
// 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,imin(data_time,data_time_off));
    {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,"lchop");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // 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,reffreq,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 = 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;
    }
    // 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;
    }
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    int load_datatime = imax(data_time_guess,data_time_off_guess);
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,effResolution{0},load_datatime,backendreadoutparms));
    int perfreqtime = 2 * (data_time_guess * n_switch_on_guess + data_time_off_guess * n_switch_off_guess + tunedelay);
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_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;
}

/////////////////////////////////////////////////////////////////////////
// Auxiliary routine to check the actual duration of telescope lines
// 
{int,int} procedure OtfTelescopeLine {
    int line_inttime = 10; // actual integration time in OTF line
    int line_telescope = 11; // duration of an OTF line from spacecraft
}{
    // Initialize
    int line_time = line_inttime;
    int line_start = 0;
    // The telescope slew can be a bit further than requested
    if(line_telescope < line_inttime) {
        CError("OTF scan length returned by telescope too short for instrument.");
    }
    if(line_telescope > line_inttime) {
        line_time = line_telescope;
        line_start = (line_telescope - line_inttime) / 2;
    }

    return {line_time,line_start};
}

// 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};
}

// Single zero measurement 
block WBS_Zero_block HIFI 6015 {
}{
    // dummy parameters for configuration reader
    string band = "4a";
    // HIFI band
    double lo_freq = 978200.0;
    // LO frequency
    // Get delays 
    {double,string}[] result = ConfigurationReader("name_delays",["wbs_zero_delay"],band,lo_freq);
    int wbs_zero_delay = iround(result[0]{0});
    int data_time = wbs_zero_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};
    // set data rates
    non_ess_hk_data_rate(fdataparms{1}[2] / 1024.0);
    data_rate(fdataparms{1}[0] / 1024.0);
    // Call commands
    Hifi_HIFI_WBS_Zero($BBID);
    delay(wbs_zero_delay);
    // reset data rates
    non_ess_hk_data_rate(fdataparms{1}[1] / 1024.0);
    data_rate(0.0);
    // additional delay for packet transmission
    // Not needed if followed by commands without science packets
    // delay(readout);
}

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;
}

// 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};
}

// 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);
}

//////////////////////////////////////////////////////////////////////
// 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}};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

/////////////////////////////////////////////////////////////////
// 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,imin(data_time,data_time_off));
    {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,"fs");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // 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,reffreq,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 = 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;
    }
    // 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;
    }
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    tunedelay = 2 * tunedelay;
    int load_datatime = imax(data_time_guess,data_time_off_guess);
    int loadlength = duration(SScanDoubleLoadMeasurement(band,reffreq,reffreq,freq_throw,true,effResolution{0},load_datatime,backendreadoutparms));
    int perfreqtime = 2 * (data_time_guess * n_switch_on_guess + data_time_off_guess * n_switch_off_guess + tunedelay);
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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});
    ChopMessages(true,data_time,n_int_on);
    RasterSizeMessages({0.0,0.0},stepsize,2,npoints,true);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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);
}

/////////////////////////////////////////////////////////////////
// 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};
    {{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,"lchop");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // 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);
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    int load_datatime = iceil(retvalues[0]{1});
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,effResolution{0},load_datatime,backendreadoutparms));
    int perfreqtime = 2 * load_datatime + tunedelay;
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    retvalues[1] = {"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)};

    return retvalues;
}

// 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);
}

// 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]);
}

/////////////////////////////////////////////////////////////////
// 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
    string refmode = "dbs" in ["dbs","fs","lchop"]; // reference scheme to use
    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,refmode);
    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
    // adjust reference frequency to be within the grid
    gfref = GetFReference(band,freqgrid[0],freqgrid[nfreq - 1]);
    reffreq = gfref{0};
    // 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>");
    message("Frequency used for noise computation: " + reffreq / 1000.0 + "GHz.<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;
        }
    }
    // 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
    int theindex = 0;
    for(int i = 0 .. n_cycles - 1) {
        for(int i1 = 0 .. n_loadnods - 1) {
            theindex = theindex + n_loadinterval * 2 * scansize;
            if(theindex < numpoints) {
                longslew = imin(longslew,telescopetimes[theindex + 6]);
            }
        }
    }

    return longslew;
}

// 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";
    // We chop now from plusZ tu minusZ, i.e. in negative direction
    // The nodding has to go into the opposite direction
    double[] nodpatt = CalibrationReader("skychopthrow",[lstring,astring],band,lo_freq);
    // restrict to allowed range
    double patt = (nodpatt[1] + 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();
        }
    }
}

////////////////////////////////////////
// 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];
}

/////////////////////////////////////////////////////////////////
// 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];
}

// 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);
}

//////////////////////////////////////////////////////////////////////////////
// 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);
}

//////////////////////////////////////////////////////////////////////
// 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,true);
}

// 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;
}

//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);
    //
}

//  LCU configuration into DISSIPATIVE mode, procedure
procedure LCU_config_dissipative_w_D2_proc_aot {
    string band = "1a" in ["1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //
    //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[] cresult = CalibrationReader("name_lcu_dissipative",["lo_freq"],band,0.0);
    double lo_freq = cresult[0];
    //
    cresult = CalibrationReader("name_lcu_safe_values",["pl_c","m1_v","m2_v","m3_v","g1_v","g2_v","d1_v","d2_v"],band,lo_freq);
    double plevel_v = cresult[0];
    double m1_v = cresult[1];
    double m2_v = cresult[2];
    double m3_v = cresult[3];
    double gate1_v = cresult[4];
    double gate2_v = cresult[5];
    double drain1_v = cresult[6];
    double drain2_v = cresult[7];
    //
    cresult = CalibrationReader("name_lcu_dissipative",["d2_step","nx"],band,lo_freq);
    int d2_step = iround(cresult[0]);
    int freq_nx = ifloor(cresult[1]);
    //
    //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
    {double,string}[] 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 config_lo_delay = iround(result[0]{0});
    //
    //Send command: expect that we have already switched to NOMINAL
    HIFI_Configure_LCU_dissipative_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);
    //
    // Put heaters explicitly to 4 V
    mois_step("Set heaters to normal mode value");
    HL_heater_block_aot(band,"nominal");
    //
    //Configure to Dissipative
    Set_LO_Dissipative_block_aot();
}

// 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.");
    }
}

//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
}

// 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);
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

//////////////////////////////////////////////////////////////////////
// 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);
    // Combined sideband scaling
    double[] gssb = InterpolateGssb(band,reffreq);
    double avgainfac = 0.5 / gssb[0] + 0.5 / gssb[1];
    double rescalefac = gssb[1] * avgainfac;
    // 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} * gssb[0] * multiplier;
    noisevalues{1} = noisevalues{1} * gssb[0] * 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 decnoise_lores = noisevalues{0} / sqrt(gssb[0] * gssb[0] + gssb[1] * gssb[1]);
        double decnoise_hires = noisevalues{1} / sqrt(gssb[0] * gssb[0] + gssb[1] * gssb[1]);
        double indnoise_lores = noisevalues{2} * rescalefac;
        double indnoise_hires = noisevalues{3} * rescalefac;
    } else {
        // Get single sideband noise equivalent
        decnoise_lores = noisevalues{0} * avgainfac;
        decnoise_hires = noisevalues{1} * avgainfac;
        indnoise_lores = noisevalues{2} * rescalefac;
        indnoise_hires = noisevalues{3} * rescalefac;
    }
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {decnoise_lores,decnoise_hires,indnoise_lores,indnoise_hires,noisevalues{4}};
}

// 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];
}

////////////////////////////////////
// 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});
    ChopMessages(true,data_time,n_int_on);
    RasterSizeMessages(lineDistance,stepsize,nlines,npoints,false);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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};
}

/////////////////////////////////////////////////////////////////
// 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();
        }
    }
}

/////////////////////////////////////////////////////////////////
// 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});
    ChopMessages(true,data_time,n_int_on);
    RasterSizeMessages(lineDistance,stepsize,nlines,npoints,false);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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};
}

/////////////////////////////////////////////////////////////////
// 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};
}

/////////////////////////////////////////////////////////////////
// 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,true);
    //
    //Magnet tuning: use either HRS or WBS, not for bands 1,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
    // Extra stabilization only for HEB bands
    if(band == "6a" || band == "6b" || band == "7a" || band == "7b") {
        LO_tuning_block_aot(band,lo_freq_2 / 1000.0,lo_freq_setting,tuningbackend,false,true,true,true);
    } else {
        LO_tuning_block_aot(band,lo_freq_2 / 1000.0,lo_freq_setting,tuningbackend,false,true,true,false);
    }
    //
}

// Last message of an observing mode - check for polarizations, close message body
procedure PolarizationMessage {
    bool hrs1used = true;
    bool hrs2used = true;
    bool wbs1used = true;
    bool wbs2used = true;
}{
    // Check whether both polarizations are used in at least one spectrometer system
    if(hrs1used && hrs2used || wbs1used && wbs2used) {
        message("</body></html>");
    } else {
        // Raise warning if not
        message("<p><strong>");
        message("Beware that only one polarization is observed so that the actual noise will be higher!");
        message("</strong></p>");
        message("</body></html>");
    }
}

////////////////////////////////////
// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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;
}

////////////////////////////////////////
// Procedure to calculate the pre timing
//
{int,int,int,int,int,int,int,int,int,bool,int,int,int} procedure DBS_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 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_FCal(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};
}

////////////////////////////////////
// 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});
    ChopMessages(false,data_time,n_switch_on);
    RasterSizeMessages({0.0,0.0},stepsize,2,npoints,true);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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 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
    bool extradelay = true; //whether extra settling time is needed after chain is configured
}{
    //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","gate1_v"],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];
    //For 6b, we need a freq-dependent G1V
    if(band == "6b") {
        gate1_v = result[5]{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;
    //
    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;
    // has to match tune_range_factor in LOSettlingTime
    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);
    //
    // Commanding of new parameters only if needed
    if(newsetting) {
        int config_lo_delay = LOSettlingTime(band,rest_lofreq,true,extradelay);
        //
        //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
        if(lo_freq < 535.5) {
            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);
        } else {
            Hifi_HIFI_Load_vector_nom_1a($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 == "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();
}

//Set HIFI from standby1 to dissipative1 mode, mode
//LOU band hard-coded to band 0
obs HifiEngSetFromStandby_I_IntoDissipative_I {
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing("0","none");
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(HifiSetFromStandby_I_IntoDissipative_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) {
            // switch to nominal settings
            HifiSetFromStandby_I_IntoDissipative_I();
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

// 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);
        }
    }
}

// Recalculate and verify LCU memory checksum
block LcuChecksumRecalc_aot HIFI 7905 {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
}{
    //Check critical program first
    string block_IF_NOK = "YES";
    LcuChecksumRecalcSegmented_aot(band,"Critical",block_IF_NOK);
    //Check safe program then
    block_IF_NOK = "YES";
    LcuChecksumRecalcSegmented_aot(band,"Safe",block_IF_NOK);
    //Check table finally
    block_IF_NOK = "NO";
    LcuChecksumRecalcSegmented_aot(band,"Table",block_IF_NOK);
    //ICU PM-low check - HIFI-3662 - Activated in cycle 26
    OBS_SEU_check_aot("PM_LOW");
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

///////////////////////////////////////////////////////
// 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");
}

//  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];
    //
    //Send command
    Hifi_HIFI_Conf_f_LCU_noretune($BBID,freq_nx,lsu_main,lsu_offset);
    //
    int config_lo_delay = LOSettlingTime(band,rest_lofreq,false,true);
    delay(config_lo_delay);
    //Store settings into available register
    if(fswstorage) {
        HIFI_HL_store_tm_proc_fm();
    }
}

/////////////////////////////////////////////////////////////////
// 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});
    ChopMessages(false,data_time,n_switch_on);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

// 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);
    //
}

//////////////////////////////////////////////////////////////////////////
// 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
    //
}

//Set HIFI to dissipative II from dissipative I - laser status handled by configwbs.config
obs HifiEngSetFromDissipative_I_IntoDissipative_II {
    string band_dissipate = "4a" 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("0","none");
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(HifiSetFromDissipative_I_IntoDissipative_II(band_dissipate));
    // 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
            HifiSetFromDissipative_I_IntoDissipative_II(band_dissipate);
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

//////////////////////////////////////////////////////////////////////
// Messages displaying the map size
procedure RasterSizeMessages {
    {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 = 1; // Number of rows in the map;
    int npoints = 10; // Number of points per row 
    bool isCross = false; // Whether it is a cross map
}{
    // Raster 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);
    // Line messages
    if(isCross) {
        message("The observed map consists of 2 crossing lines.<br>");
    } else {
        if(nlines > 1) {
            // Line parameters
            double linestep = 0.5 / 3600.0;
            double d2 = AngleVectorLength(linedistance);
            d2 = double(iceil(d2 / linestep)) * linestep * 3600.0;
            d2 = max(d2,2.0);
            // message
            message("The observed map consists of " + nlines + " lines with a spacing " + "of " + dformat(d2,1) + "'', covering in total " + dformat(double(nlines) * d2,1) + "''.<br>");
        } else {
            message("The observed map consists of 1 line.<br>");
        }
    }
    // Raster messages
    message("Every line contains " + npoints + " raster points with a spacing of " + dformat(d1,1) + "'', covering in total " + dformat(double(npoints) * d1,1) + "''.<br>");
}

// 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;
}

////////////////////////////////////
// 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;
}

/////////////////////////////////////////////////////////////////
// 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,"fs",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,true);
    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));
        tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq,false);
        smallstep = smallstep + 2 * tunediff;
    } 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 = n_freq_point * off_inttime + (n_freq_point - 1) * smallstep + 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};
}

//////////////////////////////////////////////////////////////////////////
// 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 - only rounding adjustment
    double eps = 1.001;
    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};
}

/////////////////////////////////////////////////////////////////
// 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;
}

//////////////////////////////////////////////////////////////////////////
// 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 - only rounding adjustment
        double eps = 1.001;
        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);
}

//////////////////////////////////////////////////////////////////////////
// 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};
}

////////////////////////////////////
// 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;
}

//////////////////////////////////////////////////////////////////////////
// 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
    {int,int} otfline = OtfTelescopeLine(lineint,tline);
    // 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};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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});
    ChopMessages(false,data_time,n_switch_on);
    RasterSizeMessages(lineDistance,stepsize,nlines,npoints,false);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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;
}

/////////////////////////////////////////////////////////////////
// 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};
}

// Procedure to get the general parameters for the telescope command
// for all engineering observations
{int,int} procedure Eng_pre_timing {
    string band = "4a"; // HIFI band
    string lcu_checksum = "none" in ["none","start","end","both"]; //chksum delay
}{
    // Init length
    int initlength = duration(HIFIInitObs());
    int hklength = duration(HIFISetHK("fast",true));
    if(lcu_checksum == "start" || lcu_checksum == "both") {
        int inithklength = duration(HIFILCUChecksumAndSetHK(band,"fast",true));
        initlength = initlength + inithklength;
    } else {
        initlength = initlength + hklength;
    }
    // Final length
    int closelength = duration(HIFICloseObs());
    if(lcu_checksum == "end" || lcu_checksum == "both") {
        int endhklength = duration(HIFILCUChecksumAndSetHKCloseObs(band,true,"fast",true));
        closelength = closelength + endhklength;
    } else {
        closelength = closelength + hklength;
    }
    // return everything

    return {initlength,closelength};
}

//////////////////////////////////////////////////////////////////////////
// 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);
    CheckDataTaking(backendreadoutparms,data_time_off);
    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 = 15000.0; // Input HRS internal LO freq. in GHz
}{
    double checked_flo = flo;
    if(checked_flo == 14400.0) {
        checked_flo = flo - 20.0;
    }
    if(checked_flo == 14420.0) {
        checked_flo = flo + 20.0;
    }
    if(checked_flo >= 17180.0) {
        IError("Impossible HRS configuration. " + "Half of the HRS subbands must have an upper edge USB frequency that is " + "at least 80 MHz below the upper boundary of the HIFI USB coverage. " + "Reduce the USB frequency of HRS subbands until this condition is met.");
    }
    if(checked_flo < 13000.0) {
        IError("Impossible HRS configuration. " + "Half of the HRS subbands have to have a lower edge USB frequency above " + "the lower boundary of the HIFI USB coverage. " + "Increase the USB frequency of HRS subbands until this condition is met.");
    }

    return checked_flo;
}

/////////////////////////////////////////////////////////////////
// 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;
}

// 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);
    //
    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);
    //
    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;
}

////////////////////////////////////
// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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
    HIFILCUChecksumAndSetHK(band,"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);
}

///////////////////////////////////////////////////////////////////
// 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};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

// 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);
    //
}

////////////////////////////////////////////////////////////////////////////
// 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();
        }
    }
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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,imin(data_time,data_time_off));
    {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,"fs");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // 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,reffreq,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 = 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;
    }
    // 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;
    }
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    tunedelay = 2 * tunedelay;
    int load_datatime = imax(data_time_guess,data_time_off_guess);
    int loadlength = duration(SScanDoubleLoadMeasurement(band,reffreq,reffreq,freq_throw,true,effResolution{0},load_datatime,backendreadoutparms));
    int perfreqtime = 2 * (data_time_guess * n_switch_on_guess + data_time_off_guess * n_switch_off_guess + tunedelay);
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_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;
}

/////////////////////////////////////////////////////////////////////////////
// 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};
}

// 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);
}

// 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;
}

////////////////////////////////////
// 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);
}

//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);
}

//////////////////////////////////////////////////////////////////////
// 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]};
}

///////////////////////////////////////////////
// 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>");
}

/////////////////////////////////////////////////////////////////
// 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};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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,"dbs");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // 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;
    }
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,effResolution{0},data_time_guess,backendreadoutparms));
    int perfreqtime = 2 * (2 * data_time_guess * n_switch_on_guess + tunedelay);
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_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;
}

/////////////////////////////////////////////////////////////////
// Procedure to compute detailed timing for a
// Spectral Scan DBS engineering mode
// 
{{int,int,int,int,int,int,int,int,int,bool,int,int,int},{int,double[]}} procedure EngSScanDBS_pre_timing {
    string band = "4a"; // HIFI band
    double reffreq = 978200.0; // Reference LO frequency in MHz
    string freqgridfile = "config_StWv_scan_onsky"; // file of frequency grids
    string scan_name = "CO(9-8)"; // name of the relevant column in the grid file
    bool retunediplexer = false; // whether to change the diplexer with freq
    bool retunelo = false; // whether to retune LO Vd2 with freq
    {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_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
}{
    //////////////////////////////////////////////////////////////////////
    // 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
    double[] freqgrid = dcolumn(freqgridfile,scan_name);
    int nfreq = length(freqgrid);
    //////////////////////////////////////////////////////////////////////
    // 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;
    // Integration time per frequency and pointing
    int inttime = 2 * n_chop * data_time;
    int readouttime = data_time;
    // Tuning delays
    int bigtunestep = duration(HIFIChangeLO(band,reffreq,reffreq,retunediplexer,retunelo));
    // Correct for variation within the band
    double lo_freq_low = freqgrid[0];
    double lo_freq_up = freqgrid[nfreq - 1];
    int tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq,retunelo);
    bigtunestep = bigtunestep + tunediff;
    // For double phases I can use the added jitterdead in both phases for tune
    int jitterdead = GetMaxTimeJitter(band,reffreq);
    int halftunestep = (bigtunestep - jitterdead + 1) / 2;
    // Duration of initial set up
    int initlength = duration(HIFIInitObs());
    initlength = initlength + duration(TuneHIFI(band,reffreq,hrs1,hrs2,wbs1{0},wbs2{0},"sscan_normal"));
    // Add time for HK readout
    int hkduration = HkReadoutTime(band,reffreq,backendreadoutparms,false);
    initlength = initlength + hkduration + bigtunestep + loadlength;
    // recompute load length during slews 
    loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,false,eff_resolution{0},data_time,backendreadoutparms));
    loadlength = loadlength + readoutdead;
    // Telescope command parameters
    int pointing = inttime + halftunestep + jitterdead;
    int n_loadinterval = n_cycles;
    // Dummy parameters for the engineering mode to use the same
    // telescope API as for the standard modes
    int n_bchop = n_chop;
    int load_spacing = 8;
    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,halftunestep,initlength,dangling},{nfreq,freqgrid}};
}

//  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","gate1_v"],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];
    //For 6b, we need a freq-dependent G1V
    if(band == "6b") {
        gate1_v = result[5]{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});
    ChopMessages(true,data_time,n_int_on);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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 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};
}

// 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};
}

/////////////////////////////////////////////////////////////////
// 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 + 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};
}

////////////////////////////////////////////////////////////////////////////
// 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;
            while(i_group <= grouplen - 1) {
                // retune
                runningfreq = freqgrid[grouporder[i_phase][i_group] + i_freqcycles * grouplen];
                HIFIChangeFreq(band,runningfreq);
                if(i_group == 1) {
                    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);
                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();
        }
    }
}

// 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);
}

/////////////////////////////////////////////////////////////////
// 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};
}

// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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);
    //
}

//////////////////////////////////////////////////////////////////////
// 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);
}

// 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;
}

// 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;
}

// 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;
}

// 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};
}

// 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];
}

// 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);
}

// 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;
}

// 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);
}

// 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];
}

/////////////////////////////////////////////////////////////////
// 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(HIFILCUChecksumAndSetHK(band,"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};
}

//////////////////////////////////////////////////////////////////////
// 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
}

// 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;
}

// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

// 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}};
}

//Set HIFI to standby I - lasers are forced to be Off.
//LOU band hard-coded to band 0
obs HifiEngSetFromDissipative_II_IntoDissipative_I {
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing("0","none");
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(HifiSetFromDissipative_II_IntoDissipative_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
            HifiSetFromDissipative_II_IntoDissipative_I();
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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,false);
    //Spectrometer attenuator tuning - on the sky or cold load
    if(target_name != "") {
        WBS_attenuators_block(band,lo_freq / 1000.0,target_name,true);
    }
}

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();
        }
    }
}

// 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};
}

// procedure called to get the instrument into standby
// with WBS lasers Off
procedure HifiSetFromDissipative_II_IntoDissipative_I {
}{
    //WBS stand-by with laser OFF
    WBS_standby_block_aot("OFF");
    //Take zero spectrum with laser off - HIFI-3425
    WBS_Zero_block();
    //LOU band 0
    //Clear potential failure mode
    Set_LO_Nominal_block_aot();
    //
    LCU_switch_off_block_aot();
    //Will put heaters to 6V
    Set_LO_Dissipative_block_aot();
    //Enable checksum computation - HIFI-3578
    //Needs HK rate to be at 1_per_10sec
    Enable_CRC_FDIR_block_ops();
}

////////////////////////////////////////////////////////////////////////////
// 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
    int tline = telescopetimes[4];
    // Time in line
    // The telescope slew can be a bit further than requested
    int line_inttime = 2 * n_perline * data_time;
    {int,int} otfline = OtfTelescopeLine(line_inttime,tline);
    int line_startdelay = otfline{1};
    ////////////////////////////////////////////////////////////////////////
    // 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
            delay(line_startdelay);
            // 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 ();
}

////////////////////////////////////
// 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;
}

////////////////////////////////////
// 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;
}

// 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);
    // Insert a Noop because previous command could have been issued in second bus slot
    Hifi_HIFI_noop();
    // 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);
}

//////////////////////////////////////////////////////////////////////
// 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,true);
}

/////////////////////////////////////////////////////////////////////////////
// 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;
}

////////////////////////////////////
// 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});
    ChopMessages(true,data_time,n_int_on);
    RasterSizeMessages({0.0,0.0},stepsize,2,npoints,true);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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};
}

////////////////////////////////////////////////////////////////////////////
// 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
    int tline = telescopetimes[4];
    // Time in line
    // The telescope slew can be a bit further than requested
    int line_inttime = 2 * n_perline * data_time;
    {int,int} otfline = OtfTelescopeLine(line_inttime,tline);
    int line_startdelay = otfline{1};
    ////////////////////////////////////////////////////////////////////////
    // 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
            delay(line_startdelay);
            // 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();
        }
    }
}

// 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};
}

//TM to enable autonomous function on LCU checksum
block Disable_CRC_FDIR_block_ops HIFI 6860 {
}{
    // BBID needs to be set manually as the main TC command has no BBID argument
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    Hifi_HIFI_LCU_mem_check_off();
    delay(1);
    //
}

// 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
    // 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,"fs");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // inherit from fs-noref mode
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {string,double,double}[] retvalues = HifiPointProcFSwitchNoRefSequencerInit(naifid,ra,dec,band,reffreq,freq_throw,effResolution,narrowReference,hr1,hr2,wb1,wb2,data_time,n_cycles,load_interval,docommands);
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    tunedelay = 2 * tunedelay;
    int load_datatime = iceil(retvalues[0]{1});
    int loadlength = duration(SScanDoubleLoadMeasurement(band,reffreq,reffreq,freq_throw,true,effResolution{0},load_datatime,backendreadoutparms));
    int perfreqtime = 2 * load_datatime + tunedelay;
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    retvalues[1] = {"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)};

    return retvalues;
}

//////////////////////////////////////////////////////////////////////////
// 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,int} otfline = OtfTelescopeLine(line_inttime,tline);
    int line_time = otfline{0};
    // 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};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

/////////////////////////////////////////////////////////////////
// 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("0","none");
    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});
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posofftime,timeefficiency,efficiency,relnoise,fs);
}

/////////////////////////////////////////////////////////////////
// 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};
}

/////////////////////////////////////////////////////////////////
// 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};
    // We rely on the sequencer to determine the best group length
    // For n_cycles>1 it has to be unity, everything else is rejected
    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,"dbs",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,true);
    bigtunestep = bigtunestep + tunediff;
    if(n_freq_point > 1) {
        int smallstep = duration(HIFIChangeFreq(band,reffreq));
        tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq,false);
        smallstep = smallstep + tunediff;
    } 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 
    int[] secondside = [];
    // Central point
    secondside[0] = center;
    // Second side stepping
    counter = 1;
    i1 = center - 2;
    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;
    }
    // Final point
    if(center > 0) {
        secondside[counter] = center - 1;
    }
    // Return
    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};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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,"fs");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // inherit from fs-noref mode
    // spectral scans always use the full bandwidth for reference
    bool narrowReference = false;
    {string,double,double}[] retvalues = HifiPointProcFSwitchNoRefSequencerInit(naifid,ra,dec,band,reffreq,freq_throw,effResolution,narrowReference,hr1,hr2,wb1,wb2,data_time,n_cycles,load_interval,docommands);
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    tunedelay = 2 * tunedelay;
    int load_datatime = iceil(retvalues[0]{1});
    int loadlength = duration(SScanDoubleLoadMeasurement(band,reffreq,reffreq,freq_throw,true,effResolution{0},load_datatime,backendreadoutparms));
    int perfreqtime = 2 * load_datatime + tunedelay;
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_range = 1;
    }
    retvalues[1] = {"n_freq_point",double(n_freq_point_guess),double(n_freq_point_range)};

    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;
}

// Procedure to support systematic LCU CRC computation
// together with standard HK configuration - HIFI-3120
procedure HIFILCUChecksumAndSetHK {
    string band = "1a" in ["0","1a","1b","2a","2b","3a","3b","4a","4b","5a","5b","6a","6b","7a","7b"]; // HIFI band
    string speed = "normal" in ["fast","normal","slow"]; // Select HK rate
    bool active = false; // Whether to actively query the spectrometers
}{
    HIFISetHK(speed,active);
    LcuChecksumRecalc_aot(band);
}

////////////////////////////////////////////////////////////////////////
// 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};
}

//////////////////////////////////////////////////////////////////////////
// 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);
}

// Special message for DBS modes
procedure ChopMessages {
    bool fastChop = true; // whether fast-chop is used
    int data_time = 4; // data dump interval
    int n_switch_on = 2; // number of cycles
}{
    if(fastChop) {
        double phaselength = double(data_time) / double(2 * n_switch_on);
    } else {
        phaselength = double(data_time);
    }
    double chopfreq = 1.0 / (2.0 * phaselength);
    message("This corresponds to a chop phase length of <strong> " + phaselength + "</strong>s, or a chopper frequency of <strong> " + chopfreq + "</strong>Hz, respectively.", 2);
    message("</p>");
    message("<p>");
}

// 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);
}

//////////////////////////////////////////////////////////
// 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;
    }
    bool isOffAtPoint = false;
    ////////////////////////////////////////////////////////////////////////
    // 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
            // Check whether we are in a cross mode using computed OFF
            isOffAtPoint = iscross && inod % 2 == 0;
            // Configure measurement
            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) {
                if(isOffAtPoint) {
                    HIFIHalfChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
                } else {
                    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 
            if(isOffAtPoint) {
                HIFIHalfChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
            } else {
                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();
        }
    }
}

/////////////////////////////////////////////////////////////////
// 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,imin(data_time,data_time_off));
    {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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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;
}

//////////////////////////////////////////////////////////////////////
// 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);
    // Combined sideband scaling
    double[] gssb = InterpolateGssb(band,reffreq);
    double avgainfac = 0.5 / gssb[0] + 0.5 / gssb[1];
    double rescalefac = gssb[1] * avgainfac;
    // Correct for multiple frequencies
    double multiplier = sqrt(1.0 / double(nfreq));
    noisevalues{0} = noisevalues{0} * gssb[0] * multiplier;
    noisevalues{1} = noisevalues{1} * gssb[0] * 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 decnoise_lores = noisevalues{0} / sqrt(gssb[0] * gssb[0] + gssb[1] * gssb[1]);
        double decnoise_hires = noisevalues{1} / sqrt(gssb[0] * gssb[0] + gssb[1] * gssb[1]);
        double indnoise_lores = noisevalues{2} * rescalefac;
        double indnoise_hires = noisevalues{3} * rescalefac;
    } else {
        // Get single sideband noise equivalent
        decnoise_lores = noisevalues{0} * avgainfac;
        decnoise_hires = noisevalues{1} * avgainfac;
        indnoise_lores = noisevalues{2} * rescalefac;
        indnoise_hires = noisevalues{3} * rescalefac;
    }
    // Return noise values and the maximum ratio of drift to radiometric noise

    return {decnoise_lores,decnoise_hires,indnoise_lores,indnoise_hires,noisevalues{4}};
}

//////////////////////////////////////////////////////////////////
// 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};
}

/////////////////////////////////////////////////////////////////
// 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];
}

//////////////////////////////////////////////////////////////////////
// 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};
}

// 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);
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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,imin(data_time,data_time_off));
    {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,"lchop");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // 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,reffreq,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 = 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;
    }
    // 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;
    }
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    int load_datatime = imax(data_time_guess,data_time_off_guess);
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,effResolution{0},load_datatime,backendreadoutparms));
    int perfreqtime = 2 * (data_time_guess * n_switch_on_guess + data_time_off_guess * n_switch_off_guess + tunedelay);
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_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 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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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});
    ChopMessages(false,data_time,n_switch_on);
    RasterSizeMessages({0.0,0.0},stepsize,2,npoints,true);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

// 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);
}

// 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};
}

//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);
    //
}

// 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});
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posinttime,timeefficiency,efficiency,relnoise,false);
}

////////////////////////////////////
// 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,[[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 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

//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};
}

/////////////////////////////////////////////////////////////////
// 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};
}

/////////////////////////////////////////////////////////////////
// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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}};
}

/////////////////////////////////////////////////////////////////
// Spectral scan in DBS observing modes
// 
// Implemented as procedure returning time and noise levels for HSPOT
{int,double,double,double,double,double} obs HifiEngSScanDBS {
    /* 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 freqgridfile = "config_StWv_scan_onsky"; // file of frequency grids
    string scan_name = "CO(9-8)" in ["CO(5-4)","CO(6-5)","CO(7-6)","CO(8-7)","CO(9-8)","CO(10-9)","CO(13-12)","N+","C+","CO(5-4)_StWv"]; // name of the relevant column in the grid file
    bool retunediplexer = false; // whether to change the diplexer with freq
    bool retunelo = false; // whether to retune LO Vd2 with freq
    /* 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_cycles = 1 in [1,600]; //  Number of half OFF-ON-ON-OFF cycles at one frequency
}{
    //////////////////////////////////////////////////////////////////////
    // Parameters inherited from the standard AOTs but kept constant
    {double,double} effResolution = {1.1,1.1};
    // Minimum and maximum goal resolution of the calibrated data in MHz
    int load_interval = 4 * data_time * n_switch_on * n_cycles;
    // Get band and LO_freq freom reference configuration file
    string band = slookup("config_eng_scan",scan_name,"band");
    double lo_freq = dlookup("config_eng_scan",scan_name,"ref_freq");
    //////////////////////////////////////////////////////////////////////
    // Start of observing mode
    OpenMessages("HIFI Engineering - Spectral Scan DBS slowChop",{data_time,0,0,n_switch_on,0,0,0,1,n_cycles,load_interval});
    ChopMessages(false,data_time,n_switch_on);
    // First get the backend configuration
    {{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 first part of the timing computer
    {{int,int,int,int,int,int,int,int,int,bool,int,int,int},{int,double[]}} pre_timing = EngSScanDBS_pre_timing(band,lo_freq,freqgridfile,scan_name,retunediplexer,retunelo,effResolution,hr1,hr2,wb1,wb2,data_time,n_switch_on,n_cycles);
    // frequency parameters
    int freqnumber = pre_timing{1}{0};
    double[] freqgrid = pre_timing{1}{1};
    int n_total = freqnumber * 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,lo_freq,"",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} post_timing = EngSScanDBS_post_timing(pre_timing{0},telescopetimes,freqnumber,n_cycles);
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the telescope
    // Prepare telescope command
    tpar = DBS_telescope(naifid,onPosition,band,lo_freq,"",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 
    // (The structure is more complex than needed, but allows to use normal
    // AOT telescope routines)
    int shiftlength = post_timing{1}{10};
    int initlength = post_timing{1}{11};
    //////////////////////////////////////////////////////////////////////
    // Now the observation starts for the instrument
    // Initialize time
    sync();
    int startobs = time();
    // Call instrument commands
    EngSScanDBS_commanding(band,lo_freq,effResolution,hr1,hr2,wb1,wb2,freqgrid,retunediplexer,retunelo,data_time,n_switch_on,n_cycles,n_total,shiftlength,startobs,telescopetimes);
    // 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
    //
    // efficiency parameters
    double tscan = post_timing{2};
    double tdead = post_timing{3};
    //
    // get additional dead times from instrument
    {double,double,double} tact = DBS_deadtimes(band,lo_freq,hr1,hr2,wb1,wb2,data_time,n_switch_on,0,tdead);
    //
    // Call noise computer
    {double,double,double,double,double} noisevalues = DBS_noisecomputer(band,lo_freq,effResolution,false,true,n_cycles,tscan,tact);
    // Close all messages
    message("</p></body></html>");
    // 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 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};
}

//////////////////////////////////////////////////////////////////////////
// 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);
    CheckDataTaking(backendreadoutparms,data_time_off);
    // 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};
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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});
    ChopMessages(true,data_time,n_int_on);
    RasterSizeMessages(lineDistance,stepsize,nlines,npoints,false);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

// 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,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();
        }
    }
}

////////////////////////////////////
// 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});
    // 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
    bool usesVectorScan = false; // whether to make room for the vector scan 
}{
    // Translate MHz from AOT API to configuration table in GHz
    // Include redshift correction: maxredshift=1 + 30.7km/s / 299999.6km/s;
    double maxredshift = 1.0001023;
    double lofreq_ref = reffreq / 1000.0;
    double lofreq_min = lo_freq / 1000.0 / maxredshift;
    double lofreq_max = lo_freq_up / 1000.0 * maxredshift;
    //Some sanity checks
    if(lofreq_min >= lofreq_max) {
        error("Min LO frequency for SScan is higher than max one");
    }
    // Reference value
    int ref_delay = LOSettlingTime(band,lofreq_ref,usesVectorScan,false);
    //Readout content of LCU Vd2 table only once out of loop
    string tab = "configlcu" + band + "tune.config";
    int maxindex = table_size(tab);
    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);
    // Extend table to leave space for extrapolation and velocity correction
    index_min = imax(index_min,1);
    index_max = imin(index_max + 1,maxindex);
    //Loop on all bracketted indices
    // Maximum value
    double max_vd2 = 0.0;
    for(int i = index_min - 1 .. index_max - 1) {
        max_vd2 = max(allVd2[i],max_vd2);
    }
    //Get auxiliary numbers
    if(usesVectorScan) {
        double tune_range_factor = 1.05;
    } else {
        tune_range_factor = 1.0;
    }
    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);
    // Get delay for maximum vd2
    int delay_max = iceil(result[0]{0} + (max_vd2 * tune_range_factor - drain2_safe) / result[1]{0});
    // 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);
    }
}

// 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];
}

/////////////////////////////////////////////////////////////////
// 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,"lchop",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,true);
    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));
        tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq,false);
        smallstep = smallstep + tunediff;
    } 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};
}

/////////////////////////////////////////////////////////////////
// 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};
}

//////////////////////////////////////////////////////////////////////
// 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,true);
}

// 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 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();
        }
    }
}

//////////////////////////////////////////////////////////////////////////
// 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);
        }
    }
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

////////////////////////////////////
// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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","gate1_v"],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];
    //For 6b, we need a freq-dependent G1V
    if(band == "6b") {
        gate1_v = result[5]{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};
}

// Mirror an angular direction
double procedure MirrorDirection {
    double angle = 0.0; // Original angle
}{
    double fullcircle = 360.0;

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

/////////////////////////////////////////////////////////////////
// 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
    string refmode = "dbs" in ["dbs","fs","lchop"]; // reference scheme to use
}{
    // 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,refmode);
    int grouplen = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);

    return grouplen;
}

//Set HIFI to dissipative2 mode, mode
obs HifiEngSetFromNormal_IntoDissipative_II {
    string band = "4a" 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(band,"both");
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(HifiSetFromNormal_IntoDissipative_II(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();
            HIFILCUChecksumAndSetHK(band,"fast",true);
        }
        if(state[0] == 3) {
            // switch to nominal settings
            HifiSetFromNormal_IntoDissipative_II(band);
        }
        if(state[0] == 5) {
            HIFILCUChecksumAndSetHKCloseObs(band,true,"normal",true);
            HIFICloseObs();
        }
    }
}

//////////////////////////////////////////////////////////////////////////////
// routines needed for IST, but not part of observing modes
//////////////////////////////////////////////////////////////////////////////
//Check ICU memories, mode
obs HifiEngOBS_SEU_check {
}{
    // pre_timing
    {int,int} pre_timing = Eng_pre_timing("0","none");
    int initlength = pre_timing{0};
    int closelength = pre_timing{1};
    int mainduration = duration(OBS_SEU_check_block_ops("ALL"));
    // 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
            OBS_SEU_check_block_ops("ALL");
        }
        if(state[0] == 5) {
            HIFISetHK("normal",true);
            HIFICloseObs();
        }
    }
}

/////////////////////////////////////////////////////////////////
// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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 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};
}

//////////////////////////////////////////////////////////////////////////
// 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};
}

////////////////////////////////////
// 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};
    // We rely on the sequencer to determine the best group length
    // For n_cycles>1 it has to be unity, everything else is rejected
    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,"dbs",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,true);
    bigtunestep = bigtunestep + tunediff;
    if(n_freq_point > 1) {
        int smallstep = duration(HIFIChangeFreq(band,reffreq));
        tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq,false);
        smallstep = smallstep + tunediff;
    } 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,"dbs");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // 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;
    }
    // update range from updated data_time
    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;
    }
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    int load_datatime = GetStdLoadReadout(band,reffreq);
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,effResolution{0},load_datatime,backendreadoutparms));
    int perfreqtime = 2 * (data_time_guess * n_switch_on_guess + tunedelay);
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_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;
}

// 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;
}

// OBS SFT, block
block OBS_SEU_check_block_ops HIFI 7931 {
    string memory_area = "PM_LOW" in ["PM_LOW","PM_HIGH","DM","EEPROM1","EEPROM2","BSW","ALL"];
}{
    // StartBlock_ops(); - not available in ASTR CUS
    mois_spacon("In the following command, the second parameter (OBS_ID) must be replaced by the parameter value according to the list provided by the instrument ICC.");
    Hifi_HIFI_Set_OBS_ID($BBID,$OBSID);
    if(memory_area == "ALL") {
        //De-activate S/S HK collection during the checks
        Hifi_HIFI_Housekeeping_off();
        delay(1);
    }
    //Parameters for PM-low: this is for OBS6.4.1
    int check_start = ilookup("config_icu_memory.config","PM_LOW","start");
    int check_end = ilookup("config_icu_memory.config","PM_LOW","end_or_length");
    int check_crc = ilookup("config_icu_memory.config","PM_LOW","crc");
    //PM_LOW check
    if(memory_area == "PM_LOW" || memory_area == "ALL") {
        mois_spacon("In the following TC, parameters HP231197, HP232197 and HP233197 should be treated as formal parameters");
        Hifi_HIFI_check_PM_memory(check_start,check_end,check_crc);
        delay(3);
        mois_tmcheck("Verify that no 1,8 has been generated. Otherwise, please inform the HIFI ICC.");
    }
    //PM_HIGH check
    if(memory_area == "PM_HIGH" || memory_area == "ALL") {
        check_start = check_start + 0x3ffff;
        check_end = check_end + 0x3ffff;
        mois_spacon("In the following TC, parameters HP231197, HP232197 and HP233197 should be treated as formal parameters");
        Hifi_HIFI_check_PM_memory(check_start,check_end,check_crc);
        delay(3);
        mois_tmcheck("Verify that no 1,8 has been generated. Otherwise, please inform the HIFI ICC.");
    }
    //PROM copy into PM (BSW) check
    if(memory_area == "BSW" || memory_area == "ALL") {
        check_start = ilookup("config_icu_memory.config","BSW","start");
        check_end = ilookup("config_icu_memory.config","BSW","end_or_length");
        check_crc = ilookup("config_icu_memory.config","BSW","crc");
        mois_spacon("In the following TC, parameters HP231197, HP232197 and HP233197 should be treated as formal parameters");
        Hifi_HIFI_check_PM_memory(check_start,check_end,check_crc);
        delay(1);
        mois_tmcheck("Verify that no 1,8 has been generated. Otherwise, please inform the HIFI ICC.");
    }
    //DM check
    if(memory_area == "DM" || memory_area == "ALL") {
        //There are three segments to consider here
        check_start = ilookup("config_icu_memory.config","DM1","start");
        int check_length = ilookup("config_icu_memory.config","DM1","end_or_length");
        mois_spacon("In the following TCs, parameters HP003197 and HP004197 should be treated as formal parameters");
        Hifi_HIFI_check_memory("DM",check_start,check_length);
        delay(1);
        //
        check_start = ilookup("config_icu_memory.config","DM2","start");
        check_length = ilookup("config_icu_memory.config","DM2","end_or_length");
        Hifi_HIFI_check_memory("DM",check_start,check_length);
        delay(1);
        //
        check_start = ilookup("config_icu_memory.config","DM3","start");
        check_length = ilookup("config_icu_memory.config","DM3","end_or_length");
        Hifi_HIFI_check_memory("DM",check_start,check_length);
        delay(1);
        //
    }
    //EEPROM1 check: done in two chunks due to length limit to 16 bits
    if(memory_area == "EEPROM1" || memory_area == "ALL") {
        check_start = ilookup("config_icu_memory.config","EEPROM1_1","start");
        check_length = ilookup("config_icu_memory.config","EEPROM1_1","end_or_length");
        mois_spacon("In the following TC, parameters HP003197 and HP004197 should be treated as formal parameters");
        Hifi_HIFI_check_memory("EEPROM",check_start,check_length);
        delay(1);
        check_start = ilookup("config_icu_memory.config","EEPROM1_2","start");
        check_length = ilookup("config_icu_memory.config","EEPROM1_2","end_or_length");
        mois_spacon("In the following TC, parameters HP003197 and HP004197 should be treated as formal parameters");
        Hifi_HIFI_check_memory("EEPROM",check_start,check_length);
        delay(1);
    }
    //EEPROM2 check: done in two chunks due to length limit to 16 bits
    if(memory_area == "EEPROM2" || memory_area == "ALL") {
        check_start = ilookup("config_icu_memory.config","EEPROM2_1","start");
        check_length = ilookup("config_icu_memory.config","EEPROM2_1","end_or_length");
        mois_spacon("In the following TC, parameters HP003197 and HP004197 should be treated as formal parameters");
        Hifi_HIFI_check_memory("EEPROM",check_start,check_length);
        delay(1);
        check_start = ilookup("config_icu_memory.config","EEPROM2_2","start");
        check_length = ilookup("config_icu_memory.config","EEPROM2_2","end_or_length");
        mois_spacon("In the following TC, parameters HP003197 and HP004197 should be treated as formal parameters");
        Hifi_HIFI_check_memory("EEPROM",check_start,check_length);
        delay(1);
    }
    //
    if(memory_area == "ALL") {
        //Re-activate S/S HK collection during the checks
        Hifi_HIFI_Housekeeping_on("1_pkt_per_s","ON","ON","ON","ON","ON","ON");
    }
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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});
    ChopMessages(true,data_time,n_int_on);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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]);
}

// 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);
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

// 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;
    }
    bool isOffAtPoint = false;
    ////////////////////////////////////////////////////////////////////////
    // 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
            // Check whether we are in a cross mode using computed OFF
            isOffAtPoint = iscross && inod % 2 == 0;
            // Configure measurement
            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) {
                if(isOffAtPoint) {
                    HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
                } else {
                    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 
            if(isOffAtPoint) {
                HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
            } else {
                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();
        }
    }
}

////////////////////////////////////
// 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});
    ChopMessages(true,data_time,n_int_on);
    RasterSizeMessages(lineDistance,stepsize,nlines,npoints,false);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

// 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);
}

////////////////////////////////////
// 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});
    ChopMessages(true,data_time,n_int_on);
    RasterSizeMessages({0.0,0.0},stepsize,2,npoints,true);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

////////////////////////////////////
// Test mode - DBS mode with new frequency calibration
// 
{int,double,double,double,double,double} obs HifiPointProcDBS_FCal {
    /* 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 Engineering - DBS slowChop newComb",{data_time,0,0,n_switch_on,0,0,0,0,n_cycles,load_interval});
    ChopMessages(false,data_time,n_switch_on);
    // Call first part of the timing computer
    {int,int,int,int,int,int,int,int,int,bool,int,int,int} pre_timing = DBS_FCal_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_FCal_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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

////////////////////////////////////
// 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>");
        }
    }
}

//////////////////////////////////////////////////////////////////////////
// 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 - only rounding adjustment
    double eps = 1.001;
    // 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);
    // 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(iceil((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;
    }
    // A message is the only feedback mechanism that we have here.
    // Always provide messages:
    message("Each OTF line consists of " + npoints + " readouts, with a spacing of " + dformat(validstepsize * 3600.0,1) + "'', covering in total " + dformat(double(npoints) * validstepsize * 3600.0,1) + "''.<br>");
    message("Beware that the covered rectangular area is smaller" + " by up to one readout, i.e. " + dformat(validstepsize * 3600.0,1) + "'', due to a zig-zag pattern of the readouts.<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 
    if(nlines_tot > 1) {
        message("The observed map consists of " + nlines_tot + " OTF lines, with a " + "spacing of " + dformat(d2 * 3600.0,1) + "'', spanning in total " + dformat(double(nlines_tot) * d2 * 3600.0,1) + "'' perpendicular to the line " + "direction.<br>");
    } else {
        message("The observed map consists of 1 OTF line.<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.");
    }
}

// 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 * grouplen - numlong_off) * n_chop_off) / double(grouplen * 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);
}

// 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;
}

// 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];
}

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;
}

// 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);
}

//////////////////////////////////////////////////////////////////////////
// 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(n_loadinterval > 1 && (dangling_period + n_loadinterval) * 2 * scan_time > load_interval - loadlength + longslew) {
                n_loadinterval = n_loadinterval - 1;
                dangling_period = n_cycles % n_loadinterval;
            }
            n_long = n_scans * (n_cycles / n_loadinterval);
        }
        // Determine need for final load measurement
        double rest = double(n_tot % n_loadinterval) + 0.5;
    } 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;
        // Determine need for final load measurement
        rest = double((n_tot - 1) % n_loadinterval) + 1.5;
    }
    // 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;
    // Criterium for final load measurement
    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};
}

// 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);
    //
    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;
}

//TM to enable autonomous function on LCU checksum
block Enable_CRC_FDIR_block_ops HIFI 6859 {
}{
    //Needs HK rate to be at 1_per_10sec (HIFI-3578)
    // 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]);
    delay(1);
    //
    int expected_checksum = ilookup("LcuChecksumTable.config","R","normal");
    int step_time_ms = 3000;
    //Time between CRC check and HK request in msec 
    int step_time_s = 3600;
    //Frequency of checksum verification in sec 
    Hifi_HIFI_LCU_mem_check_on($BBID,step_time_ms,expected_checksum,step_time_s);
    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;
}

// 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. " + "Adjust your LO frequency and/or frequency throw.");
    }
}

/////////////////////////////////////////////////////////////////////////////
// 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
    HIFILCUChecksumAndSetHK(band,"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);
    }
    //
}

/////////////////////////////////////////////////////////////////
// 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;
}

////////////////////////////////////
// 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});
    ChopMessages(false,data_time,n_switch_on);
    RasterSizeMessages(lineDistance,stepsize,nlines,npoints,false);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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};
}

//////////////////////////////////////////////////////////////////////
// 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;
}

/////////////////////////////////////////////////////////////////
// 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};
}

//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
        if(lo_freq < 535.5) {
            Hifi_HIFI_Conf_safe_LCU_ch1a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
        } else {
            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_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};
}

/////////////////////////////////////////////////////////////////
// Second step of timing computation after telescope behaviour
// is known -  Engineering Spectral Scan DBS observing mode
// 
// This is only needed to get the consistency checks and noise computation
// 
{int,{int,int,int,int,int,int,int,int,int,bool,int,int,int},double,double} procedure EngSScanDBS_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 freqnumber = 50; // Total umber of frequencies
    int n_cycles = 1; //  Number of half OFF-ON-ON-OFF cycles at one frequency
}{
    // 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};
    // 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;
    pointing = inttime + halftunestep + jitterdead;
    // The initial time is no longer contained in the total time
    initlength = initlength - halftunestep;
    int shiftlength = halftunestep;
    //////////////////////////////////////////////////////////////////////
    // Compute total duration
    int allslews = longslew + (n_cycles - 1) * slewtime;
    int totaltime = freqnumber * (n_cycles * 2 * pointing + allslews);
    double tdead = double(allslews) / double(n_cycles);
    double tscan = double(2 * inttime) + tdead;
    //////////////////////////////////////////////////////////////////////
    // 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},tscan,tdead};
}

//////////////////////////////////////////////////////////////////////
// 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});
    // General messages
    PerformanceMessages(band,lo_freq,totaltime,posinttime,posofftime,timeefficiency,efficiency,relnoise,false);
}

// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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;
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

// 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
        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_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];
    }
    //
    //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;
}

//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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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] + 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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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;
}

// 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};
}

/////////////////////////////////////////////////////////////////////////////
// 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};
}

//  LCU configuration into NOMINAL mode, procedure
procedure LCU_config_nominal_w_D2_proc_aot {
    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_aot();
    //
    //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","gate1_v"],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];
    //For 6b, we need a freq-dependent G1V
    if(band == "6b") {
        gate1_v = result[5]{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_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);
    //
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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});
    ChopMessages(false,data_time,n_switch_on);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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);
    // 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;
    }
    bool isOffAtPoint = false;
    ////////////////////////////////////////////////////////////////////////
    // 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;
            iphase = iphase + 1;
        }
        //////////////////////////////////////////////////////////////////////
        // States for actual observations
        if(state[0] == 3) {
            // First nodding position
            // Check whether we are in a cross mode using computed OFF
            isOffAtPoint = iscross && inod % 2 == 0;
            // Configure measurement
            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) {
                if(isOffAtPoint) {
                    HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
                } else {
                    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
            if(isOffAtPoint) {
                HIFIFastChopOffIntegration(data_time,n_seq,band,lo_freq,choppars,rates);
            } else {
                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(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},load_datatime,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
            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(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},load_datatime,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},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
        if(lo_freq < 535.5) {
            Hifi_HIFI_Conf_safe_LCU_ch1a($BBID,freq_nx,lsu_main,lsu_offset,d2_step,drain2_v,curlim2_v,macro_checksum);
        } else {
            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_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();
}

// 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,false);
    //
    //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,false);
    //
}

////////////////////////////////////////////////////////////////////////////
// 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;
    int ihold = 0;
    // Do I have to make loads in short nods and subsequent holds?
    if(iscross) {
        bool holdforload = n_pointsperscan > 1;
        int phaseshift = 0;
    } else {
        holdforload = n_pointsperscan == 1 && n_loadinterval > n_cycles;
        phaseshift = 1;
    }
    bool isOffAtPoint = false;
    bool isLastPhase = false;
    ////////////////////////////////////////////////////////////////////////
    // 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
            // Sanity check
            if(runintostate && iscross) {
                CError("Ongoing integration while arriving at ON nodding position.");
            }
            // Check whether we are in a cross mode using computed OFF
            isOffAtPoint = iscross && holdforload && inod % 2 == 1;
            // Configure measurement
            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) {
                if(isOffAtPoint) {
                    HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
                } else {
                    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 
            if(isOffAtPoint) {
                HIFISlowChopOffIntegration(data_time,n_seq,band,lo_freq,rates);
            } else {
                HIFISlowChopOnIntegration(data_time,n_seq,band,lo_freq,rates);
            }
            // Final point before nod
            // Dirty trick to find out whether we are at the very last point
            isLastPhase = telescopetimes[0] + tinitslew - (time() - startobs) < 2 * data_time * n_seq;
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == 1) {
                inod = inod + 1;
            }
            // 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 == phaseshift) {
                ihold = ihold + 1;
                if(holdforload && ihold % n_loadinterval == 0 && n_load == 0 && !isLastPhase) {
                    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;
                }
                // Load measurement between two A-A or B-B phases if required
                // Time partially included in pointing
                if(n_load > 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    // Run into final hold for very last point
                    if(isLastPhase) {
                        runintostate = true;
                    }
                }
            }
            // Update phase counter
            iphase = iphase + 1;
        }
        // Second pointing phase
        if(state[0] == 7) {
            // second nod position
            // Sanity check
            if(runintostate && iscross) {
                CError("Ongoing integration while arriving at OFF nodding 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);
            // Final point before nod
            // Dirty trick to find out whether we are at the very last point
            isLastPhase = telescopetimes[0] + tinitslew - (time() - startobs) < 2 * data_time * n_seq;
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == 1) {
                inod = inod + 1;
            }
            // Special treatment for all cases where load has to be replaced by hold:
            if(iphase % n_pointsperscan == 0 && iphase / n_pointsperscan % 2 == phaseshift) {
                ihold = ihold + 1;
                if(holdforload && ihold % n_loadinterval == 0 && n_load == 0 && !isLastPhase) {
                    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;
                }
                // Load measurement between two A-A or B-B phases if required
                // Time partially included in pointing
                if(n_load > 0) {
                    delay(readoutdead);
                    LoadMeasurement(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
                    // Run into final hold for very last point
                    if(isLastPhase) {
                        runintostate = true;
                    }
                }
            }
            // Update phase counter
            iphase = iphase + 1;
        }
        // Load nod
        if(state[0] == 9) {
            // Load nod
            // Sanity check
            if(runintostate) {
                CError("Ongoing integration while starting load calibration slew.");
            }
            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) {
            if(!runintostate) {
                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}};
}

////////////////////////////////////
// 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;
}

// 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];
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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();
            HIFILCUChecksumAndSetHK(band,"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
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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,"dbs");
    int n_freq_point_guess = ifloor(nocaliblen / (stdstep * double(increment)) + 1.0);
    // 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;
    }
    // update range from updated data_time
    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;
    }
    // Additional constraint of compatibility of group size with load period
    int loadperiod = LoadPeriod(band,reffreq,effResolution{1});
    // 80% margin
    int periodlimit = loadperiod * 4 / 5;
    // elements of cycle - compute cycle duration
    int tunedelay = LOSettlingTime(band,reffreq / 1000.0,false,true);
    int load_datatime = GetStdLoadReadout(band,reffreq);
    int loadlength = duration(SScanLoadMeasurement(band,reffreq,reffreq,true,effResolution{0},load_datatime,backendreadoutparms));
    int perfreqtime = 2 * (data_time_guess * n_switch_on_guess + tunedelay);
    int cycle = perfreqtime * n_freq_point_guess + loadlength;
    if(cycle > periodlimit) {
        n_freq_point_guess = imax((periodlimit - loadlength) / perfreqtime,1);
    }
    int n_freq_point_range = 1 - n_freq_point_guess;
    if(n_freq_point_range == 0) {
        n_freq_point_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;
}

// Change LO frequency
// possibly without diplexer retuning
//
procedure HIFIChangeLO {
    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 for LO
    double reffreq = 978200.0; // LO frequency for diplexer
    bool retunediplexer = false; // whether to change the diplexer with freq
    bool retunelo = false; // whether to retune LO Vd2 with freq
}{
    if(retunediplexer) {
        ConfigureFPU(band,lo_freq,false);
    } else {
        ConfigureFPU(band,reffreq,false);
    }
    if(retunelo) {
        HIFITuneFreq(band,lo_freq,true,"");
    } else {
        HIFITuneFreqNoretune(band,lo_freq);
    }
}

////////////////////////////////////
// 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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}};
}

////////////////////////////////////
// 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;
}

//////////////////////////////////////////////////////////////////////
// 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);
}

//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);
}

/////////////////////////////////////////////////////////////////
// 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
    string refmode = "dbs" in ["dbs","fs","lchop"]; // reference scheme to use
}{
    string sindex = "nocalib_" + refmode;
    double[] nocaliblen = CalibrationReader("fscangroup",[sindex],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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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});
    ChopMessages(false,data_time,n_switch_on);
    RasterSizeMessages(lineDistance,stepsize,nlines,npoints,false);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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};
}

//////////////////////////////////////////////////////////////////
// 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};
}

/////////////////////////////////////////////////////////////////
// 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});
    ChopMessages(true,data_time,n_int_on);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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);
}

/////////////////////////////////////////////////////////////////
// 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});
    ChopMessages(false,data_time,n_switch_on);
    // 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);
    // Final message to check for both polarizations
    PolarizationMessage(hr1{0},hr2{0},wb1{0},wb2{0});
    // 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 observing mode
procedure DBS_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 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_FCal(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_FCal(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_FCal(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_FCal(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_FCal(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_FCal(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_FCal(band,lo_freq,eff_resolution{0},data_time,backendreadoutparms);
            }
            runintostate = false;
            HIFICloseObs();
        }
    }
}

////////////////////////////////////
// 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;
}

//////////////////////////////////////////////////////////////////////
// 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;
}

{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","halfbeam","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;
    double[] hrs1aux = [0.0];
    double[] hrs2aux = [0.0];
    double[] sortarr = [0.0];
    // 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 - get step sizes
    stepsize = flyCrossStep * degreesPerArcsec;
    if(flyNyquistSel) {
        double[] s = CalibrationReader("beam",["nyquist"],band,av_lo_freq);
        stepsize = s[0];
    }
    if(stepsize <= 0.0) {
        s = CalibrationReader("beam",["halfbeam"],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)};
        nlines = imax(iceil(flyY * degreesPerArcmin / stepsize),1);
        // extend map by rim for OTF
        if(modeName == "fly" || modeName == "fs-raster" || modeName == "load-raster") {
            npoints = imax(iceil((flyX * degreesPerArcmin + 1.1 * stepsize) / stepsize),2);
        } else {
            npoints = imax(iceil(flyX * degreesPerArcmin / stepsize),2);
        }
        // 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" || crossStepSize == "halfbeam") {
                s = CalibrationReader("beam",[crossStepSize],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]];
        int[] hrsUseBands = [1,1,2,2];
    } else {
        hrsUseMap = [[true,false,false,false],[true,true,false,false],[true,true,true,true],[true,true,true,true]];
        hrsUseBands = [1,2,4,4];
    }
    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
        hrs1aux = [mix - fe_hrs1_h_0,mix - fe_hrs2_h_0,mix - fe_hrs3_h_0,mix - fe_hrs4_h_0];
        hrs2aux = [mix - fe_hrs1_v_0,mix - fe_hrs2_v_0,mix - fe_hrs3_v_0,mix - fe_hrs4_v_0];
    } else {
        hrs1aux = [fe_hrs1_h_0,fe_hrs2_h_0,fe_hrs3_h_0,fe_hrs4_h_0];
        hrs2aux = [fe_hrs1_v_0,fe_hrs2_v_0,fe_hrs3_v_0,fe_hrs4_v_0];
    }
    // Order HRS subbands to assign USB frequencies to first subbands
    sortarr = DSort(hrs1aux,hrsUseBands[hrs1{1}]);
    for(int j1 = 0 .. 3) {
        hrs1{2}[j1] = sortarr[j1] * factorMHzPerGHz;
    }
    sortarr = DSort(hrs2aux,hrsUseBands[hrs2{1}]);
    for(int j2 = 0 .. 3) {
        hrs2{2}[j2] = sortarr[j2] * 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);
    // Final message to check for both polarizations
    PolarizationMessage(hrs1{0},hrs2{0},wbs1{0},wbs2{0});
    // 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 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
    int tline = telescopetimes[4];
    // Time in line
    // The telescope slew can be a bit further than requested
    int line_inttime = 2 * n_perline * data_time;
    {int,int} otfline = OtfTelescopeLine(line_inttime,tline);
    int line_startdelay = otfline{1};
    ////////////////////////////////////////////////////////////////////////
    // 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
            delay(line_startdelay);
            // 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();
        }
    }
}

/////////////////////////////////////////////////////////////////
// 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,"lchop",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,true);
    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));
        tunediff = ComputeLOTimeDifference(band,lo_freq_low,lo_freq_up,reffreq,false);
        smallstep = smallstep + tunediff;
    } 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};
}

// 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;
}

