Next Previous Contents

4. Observing Algorithms

4.1 Generic single-dish observing algorithm

All single-dish observing algorithms follow this form:

get scan parameters from parser/scheduler 
set up parameters for the scan(s)
check object visibility
configure the telescope, receiver and instrument                
quickly test the receiver and instrument with the calibration noise diode 
repeat { 
        drive to start of scan
        calibrate if required
        scan and capture data until end of scan
        bin/transform/process the data if required
        scale the data if required
        plot the data on screen for visual data qualification
        } 
until ( all scans done )
write captured data in required format to disk file

The devil, of course, lies in the details.

4.2 Receiver calibration (CALT) test program algorithm

Algorithm for a CALT replacement, using a graphical user interface. Two calibration routines are used, depending whether the receiver can be configured in absolute total power mode to give the system temperature, or only to give the receiver counts per Kelvin from firing the noise diode.

The system temperature calibration routine called by CALT has been written out as pseudocode (see later).


repeat 
{
        repeat 
        {
        // set up user interface and get configuration parameters:
        // (assumed to be a Tk/TCL front end)

        list receiver systems available - 
                user selects receiver
        (or specify a frequency based on a list of standard frequencies)

        list instruments (backends) available - 
                user selects instrument to connect to receiver

        list noise diode calibrations in Kelvins from SYPARM for selected
        instrument outputs -
                user can update for these tests if incorrect

        list number of samples to take (give default) -
                user can select number of samples

        list number of tests to do (give default = 1) -
                user can select number of tests
        }
        until ( full configuration defined and user selects "GO" )

        repeat
        {       
        ask scheduler for control of receiver and instrument

        read from STEER:
                subreflector tilt and focus, 
                UT, ST, telescope HA, RA, Dec
        configure the receiver and instrument
        connect counters to instrument outputs
        setup local oscillators (DROs, frequency synthesizers)

        if ( mode = total_power ) 
        then { do total_power_calibration }
        else { do relative_gain_calibration }
        
        // display the results on the user interface:
        display UT, ST, telescope HA, RA, Dec, subref_tilt, subref_focus
        for ( ic = 0 ; ic < Ncounters ; ic++ ) do
                {
                display "output name=", output_name[ic]
                display "nominal Tsys", Tsys_nominal
                if ( COerror = 1 ) then { display "Counter error" }
                if ( NDerror = 1 ) then { display "Noise diode not seen" }
                if ( LOerror = 1 ) then { display "no change with local osc. off" }
                if ( CperK > 0 ) then { display "Counts per Kelvin", CperK, CperK_err }
                if ( Tsys > 0 ) then { display "measured Tsys", Tsys +- Tsys_err }
                }

        write the displayed results to the log file             
        }
        until ( the selected number of tests has been done )
}
until ( user selects "QUIT")

4.3 Drift scan algorithm

This is a first attempt at expanding the generic algorithm, for a drift scan.

get scan parameters from parser/scheduler 
        (object, coordinates, scan_type, scan_start, scan_length,
        scan_rate, receiver, instrument, res_freq, bin, observing
        constraints)

set up scan parameters
        minscanlen = bwfn / cos(dec) + 0.1 degrees
        set scan_length = max (min_scan_len, scan_len_input)

        sampling interval = averaging time of
        samples coming in at 10 per second
        at say 10 samples / hpbw
                
        start_RA = POSRA (RA_of_date - scanlen/2)
        drive_RA = POSRA (start_RA - calibration_time * time_to_angle)
        endRA   = POSRA (RA_of_date + scan_len/2)
        deltRA  = RA_of_date - RA2000

check object visibility
        command_HA = PMOD (ST / deg_to_sid_secs - start_RA)

        if ( command_HA > HALIM (+90.0, dec_of_date) )
        then { object has set, so quit }
        else { object is above the horizon mask, so continue }

        if ( command_HA < HALIM (-90.0, dec_of_date) )
        then { object not risen above horizon, so quit }
        else { object is above horizon mask, so continue }

        if ( coordinates within user specification of HA, elevation, time of
        day etc ) then continue

configure the telescope, receiver and instrument                
        read system parameters from syparm, using restfreq
        connect receiver L+RCP pair to instrument L+RCP pair
        configure telescope (hyperbola tilt and focus, dichroic on/off)
        configure receiver (dual/single beam, set frequency,
        Dicke mode on/off, NAD diode on/off etc.)
        configure instrument (NAD/TP etc.)

quickly test the receiver and instrument with the calibration noise diode 
        (number_of_failures_allowed, fault_report)
        continue if faults clear within specified number_of_failures_allowed
        
carry out the scan
        drive to (drive_RA, DEC)
        wake up when on target
        if ( calibrate on this scan ) then
        { calibrate receiver (counts_per_K, error_in_counts_per_K, fault) }
        if ( RA_now > start_RA ) then { drive to start_RA, DEC }
        while ( RA_now > start_RA and RA_now < end_RA )
        do { read and save ( instrument outputs, coordinates ) }

qualify data at end of scan 
        if ( binning wanted ) { bin the outputs }
        if ( scaling wanted ) { scale the outputs to Kelvins }
        plot data on screen for visual data qualification
        (counts versus angle)

write raw or binned data to disk file

quit

4.4 Algorithm for Orthogonal Scan Mapping

JJ: I have written the algorithm in pseudo-C, which I hope is reasonably clear. The structure is quite linear, just running from top to bottom. It assumes that the scheduler has checked the input file keywords and parameters for basic errors and inconsistencies, and has done basic hardware checks and locks. I am not sure I know where the dividing line comes between the scheduler and the observing procedure, and what the observing program gets given and is expected to return. The procedure for doing the map scan is quite trivial, what is important is the way coordinates and data are handled.

In what follows I have assumed that the observing program will have access to all of the parameters in the input file, and that it writes its own data to the FITS output file. It assumes the FITS file is created by the scheduler and that the scheduler also ensures that the primary array header is populated with housekeeping information (as seen in the output file example) from the input file and SYPARM.

Commands to Steer are assumed to be via a pseudo-structure:


typedef struct { char   Identifier[9];
                 double Expires;
                 short  Coordsys;
                 short  Pointing;
                 short  Dichroic;
                 char   Feedsys[25];
                 short  Secondary;
                 double Longitude[2];
                 double Latitude[2];
                 double psi, phi, theta,
                 double Parallax } SteerComdStruc;

and returned information from Steer is assumed to be in the form of an array of this pseudo-structure:


typedef struct { double X;           /* projected coordinate of beam */
                 double Y;
                 double Longitude;   /* celestial coordinate of beam */
                 double Latitude;
                 double Azimuth;     /* horizon coordinate of beam */
                 double Elevation;
                 long   Count1;      /* counts from up to 4 v/f's */
                 long   Count2;
                 long   Count3;
                 long   Count4 } SteerRetStruct;

The mapping algorithm is:


void Mapping_Scan (OBJECT, RESTFREQ, INSTRUME, MODE, COORDTYP,
                     EQUINOX, (RA et al), (DEC et al), LONGPOLE, PROJTYPE,
                     fitsfile *FitsFilePointer);

/* local variables */

struct SteerComdStruc SteerCommand;      /* Steer command structure */
struct SteerRetStruct *SteerDataPointer; /* Steer return array */
int NumberOfSamples;                     /* returned size of Steer array */ 
                                         /* binary table header info */
char *ttype[] = {"X","Y","xxxx","yyyy","AZ","EL","LCPcount","RCPcount"};
char *tform[] = {"1E", "1E", "1E", "1E", "1E", "1E", "1J", "1J"};
char *tunit[] = { "DEG", "DEG", "DEG", "DEG", "DEG", "DEG", 
                  "COUNTS", "COUNTS" };

int status;  /* returned CFITSIO status */
             /* error returns should be trapped appropriately in code */

/* some startup stuff */

Set_up_radiometer_and_counters (RESTFREQ, INSTRUME, MODE);

SteerCommand.Identifier = OBJECT;

/* this chunk of code may be common to other observing modes too */

switch (COORDTYP)
  EQUATORIAL:
    CRVAL1 = RA; CRVAL2 = DEC;
    switch (EQUINOX)
      B1950:
        SteerCommand.Coordsys = B1950; break;
      J2000:
        SteerCommand.Coordsys = J2000; break;
      MEAN:
        SteerCommand.Coordsys = MEAN; break;
      APPARENT:
        SteerCommand.Coordsys = APPARENT; break;
      default:
        SteerCommand.Coordsys = J2000;
        GeneralPrecession (EQUINOX, 2000.0, CRVAL1, CRVAL2);
        break;
    break;
  GALACTIC:
    SteerCommand.Coordsys = GALACTIC;
    CRVAL1 = GLON; CRVAL2 = GLAT;
    break;
  ECLIPTIC:
    SteerCommand.Coordsys = ECLIPTIC;
    CRVAL1 = ELON; CRVAL2 = ELAT;
    break;
  HORIZON:
    SteerCommand.Coordsys = HORIZON;
    CRVAL1 = AZ; CRVAL2 = ALT;
    break;
  TOPOCENTRIC:
    SteerCommand.Coordsys = TOPOCENTRIC;
    CRVAL1 = HA; CRVAL2 = DEC;
    break;

  SteerCommand.Pointing = True;
  SteerCommand.Dichroic = False;   /* for now */
  SteerCommand.Feed = Some_Function_Of (RESTFREQ, INSTRUME, MODE);
  SteerCommand.Secondary = False    /* for now*/

  switch (PROJTYPE)
    NONE: 
      SteerCommand.theta = 0.0; SteerCommand.phi = 0.0; 
      SteerCommand.psi = 0.0; 
      SteerCommand.Projection = CAR;  /* what steer currently uses */
      break;
    CAR:
      SteerCommand.theta = 0.0; SteerCommand.phi = - CRVAL2; 
      SteerCommand.psi = + CRVAL1; 
      SteerCommand.Projection = CAR;  /* what steer currently uses */
      break;
    SIN:
      SteerCommand.theta = +LONGPOLE; SteerCommand.phi = 90 - CRVAL2;
      SteerCommand.psi = + CRVAL1; 
      SteerCommand.Projection = SIN;  /* not implemented in steer yet */
      break;
    TAN:
      SteerCommand.theta = +LONGPOLE; SteerCommand.phi = 90 - CRVAL2;
      SteerCommand.psi = + CRVAL1; 
      SteerCommand.Projection = TAN;  /* not implemented in steer yet */
      break;

  SteerCommand.Parallax = 0.0;

/* drive to start of scan */

if (PROJTYPE == NONE)
    /* not a proper coordinate projection */
    SteerCommand.Longitude[0] = CRVAL1 + SCANSTRT.X; 
    SteerCommand.Longitude[1] = 0.0;
    SteerCommand.Latitude[0]  = CRVAL2 + SCANSTRT.Y; 
    SteerCommand.Latitude[1]  = 0.0;
  else
    /* do projection properly */
    SteerCommand.Longitude[0] = SCANSTRT.X; SteerCommand.Longitude[1] = 0.0;
    SteerCommand.Latitude[0]  = SCANSTRT.Y; SteerCommand.Latitude[1]  = 0.0;

SteerCommand.Expires = Now + 1 hour;

Slew_Antenna_and_Wait_till_tracking (SteerCommand);

/* calibration while tracking start of scan */

Do_Antenna_Temperature_Calibration_and_Write_to_FITS_file;

/* calculate scan rates for both x and y */

SteerCommand.Longitude[1] = (SCANSTOP.X - SCANSTRT.X) / SCANTIME;
SteerCommand.Latitude[1]  = (SCANSTOP.Y - SCANSTRT.Y) / SCANTIME;

/* allocate an array of appropriate size */

SteerDataPointer = malloc (sizeof(SteerRetStruct) * (SCANTIME / 0.1 + 1));

/* go off and do scan */

Scan_Antenna_and_Log_Counters (SteerCommand, SteerDataPointer, 
                               &NumberOfSamples);

/* set up some FITS keywords and open binary table */

switch (SteerCommand.Coordsys)
  TOPOCENTRIC: ttype[2] = "HA"; ttype[3] = "DEC"; break;
  HORIZON: ttype[2] = "AZ"; ttype[3] = "EL"; break;
  APPARENT, MEAN, B1950, J2000: ttype[2] = "RA"; ttype[3] = "DEC"; break;
  GALACTIC: ttype[2] = "GLON"; ttype[3] = "GLAT"; break;
  ECLIPTIC: ttype[2] = "ELON"; ttype[3] = "ELAT"; break;

status = 0;
fits_create_tbl (FitsFilePointer, BINARY_TBL, 0, 8, ttype, tform, tunit,
                 "SCAN_TABLE", &status);

fits_write_key (FitsFilePointer, TSTRING, "TDISP1", "F8.3", 
                "recommended display format", &status);
fits_write_key (FitsFilePointer, TSTRING, "TDISP2", "F8.3", 
                "recommended display format", &status);
fits_write_key (FitsFilePointer, TSTRING, "TDISP3", "F8.3", 
                "recommended display format", &status);
fits_write_key (FitsFilePointer, TSTRING, "TDISP4", "F8.3", 
                "recommended display format", &status);
fits_write_key (FitsFilePointer, TSTRING, "TDISP5", "F8.3", 
                "recommended display format", &status);
fits_write_key (FitsFilePointer, TSTRING, "TDISP6", "F8.3", 
                "recommended display format", &status);
fits_write_key (FitsFilePointer, TSTRING, "TDISP7", "I12", 
                "recommended display format", &status);
fits_write_key (FitsFilePointer, TSTRING, "TDISP8", "I12", 
                "recommended display format", &status);

/* stuff data one row at a time into a binary table in the FITS file */
/* Count3 and Count4 ignored */

for (row = 1; row <= NumberOfSamples; row++, SteerDataPointer++)
  fits_write_col (FitsFilePointer, TFLOAT, 1, row, 1, 1, 
                  &(SteerDataPointer->X), &status);
  fits_write_col (FitsFilePointer, TFLOAT, 2, row, 1, 1, 
                  &(SteerDataPointer->Y), &status);
  fits_write_col (FitsFilePointer, TFLOAT, 3, row, 1, 1, 
                  &(SteerDataPointer->Longitude), &status);
  fits_write_col (FitsFilePointer, TFLOAT, 4, row, 1, 1, 
                  &(SteerDataPointer->Latitude), &status);
  fits_write_col (FitsFilePointer, TFLOAT, 5, row, 1, 1, 
                  &(SteerDataPointer->Azimuth), &status);
  fits_write_col (FitsFilePointer, TFLOAT, 6, row, 1, 1, 
                  &(SteerDataPointer->Elevation), &status);
  fits_write_col (FitsFilePointer, TLONG, 7, row, 1, 1, 
                  &(SteerDataPointer->Count1), &status);
  fits_write_col (FitsFilePointer, TLONG, 8, row, 1, 1, 
                  &(SteerDataPointer->Count2), &status);

/* leave scheduler to close FITS file */
 


Next Previous Contents