Example #1
0
def log_message(msg, level='info', boldtype=False, colourtext='black'):

    bold = boldtype
    colour = colourtext

    if level == 'debug':
        user_logger.debug(str(msg))
    elif level == 'info':
        user_logger.info(str(msg))
    elif level == 'warn':
        user_logger.warn(str(msg))
        colour = 'orange'
        bold = True
    elif level == 'error':
        user_logger.error(str(msg))
        colour = 'red'
        bold = True

    if not bold and colour == 'black':
        email_msg.append(timestamp() + level.upper() + ' ' + str(msg))
    elif colour != 'black' and not(bold):
        email_msg.append('<font color="{colour}">{timestamp} {level} {msg}</font>'.format(
            colour=colour, timestamp=timestamp(), level=level.upper(), msg=str(msg)))
    else:
        email_msg.append('<font color="{colour}"><b>{timestamp} {level} {msg}</b></font>'.format(
            colour=colour, timestamp=timestamp(), level=level.upper(), msg=str(msg)))
def move_antennas(ants, azim, elev):
    if (-185.0 > azim) or (azim > 275.0):
        raise ParametersExceedTravelRange("Cannot perform requested slew, "
                                          "azimuth travel range exceeded.")

    if (14.65 > elev) or (elev > 92.0):
        raise ParametersExceedTravelRange("Cannot perform requested slew, "
                                          "elevation travel range exceeded.")

    # Use slew to bypass pointing model
    ants.req.ap_slew(azim, elev)
    # Since we are not using the proxy request we will have to explicitly
    # wait for the servo brakes to open and on-target sensor to update.
    time.sleep(4)

    try:
        ants.wait('ap.on-target', True, timeout=300)
        time.sleep(2)  # Track for a bit to allow deacceleration
    except:
        user_logger.error(
            "Timed out while waiting for AP to reach starting position.")
        raise

    user_logger.info("AP has reached start position.")

    ants.req.mode('STOP')
    time.sleep(3)

    current_az = ants.req.sensor_value('ap.actual-azim')
    current_el = ants.req.sensor_value('ap.actual-elev')
    current_ridx = ants.req.sensor_value('ap.indexer-position-raw')

    user_logger.info("Azimuth readings: %s", current_az)
    user_logger.info("Elevation readings: %s", current_el)
    user_logger.info("Indexer position readings: %s", current_ridx)
Example #3
0
def compare_sensors(sensors1, sensors2, num):
    """ return True if sensors2 - sensors1 > num"""
    return_value = False
    for sen in sensors1.keys():
        if sensors2[sen] - sensors1[sen] > num:
            return_value = True
            user_logger.error('%s has changed by %g from %g to %g')
    return return_value
def stop_ants(kat):
    if not kat.dry_run and kat.ants.req.mode('STOP') :
        user_logger.info("Setting Antenna Mode to 'STOP', Powering on Antenna Drives.")
	cntr = 60
	for ant in kat.ants:
	    while ant.sensor.mode.get_value() not in ['STOP']:
                time.sleep(1)
		cntr -= 1
		if cntr < 0:
		    break
    else:
         user_logger.error("Unable to set Antenna mode to 'STOP'.")
def test_sequence(ants, disable_corrections=False, dry_run=False):

    # Disable ACU pointing corrections
    if disable_corrections:
        ants.req.ap_enable_point_error_systematic(False)
        ants.req.ap_enable_point_error_tiltmeter(False)
        if not dry_run:
            try:
                ants.wait('ap.enable-point-error-systematic', False, timeout=1)
                ants.wait('ap.enable-point-error-tiltmeter', False, timeout=1)
            except:
                user_logger.error(
                    "Failed to disable ACU pointing corrections.")
                raise
        user_logger.warning("ACU pointing corrections have been disabled.")

    for azim in [-45, 45, 135, 225]:

        # Start at low elevation
        elev = 20
        # Set this target for the receptor target sensor
        target = katpoint.Target('Name, azel, %s, %s' % (azim, elev))
        user_logger.info("Starting position: '%s' ", target.description)

        if not dry_run:
            move_antennas(ants, azim, elev)

        # Move to high elevation
        elev = 80
        # Set this target for the receptor target sensor
        target = katpoint.Target('Name, azel, %s, %s' % (azim, elev))
        user_logger.info("Move to high elevation: '%s' ", target.description)

        if not dry_run:
            move_antennas(ants, azim, elev)
            # Wait for 10 minutes before moving to next position
            user_logger.info(
                "Dwell at high elevation for 10 minutes to check if indexer slips."
            )
            time.sleep(600)

        # Return to low elevation
        elev = 20
        # Set this target for the receptor target sensor
        target = katpoint.Target('Name, azel, %s, %s' % (azim, elev))
        user_logger.info("Return to low elevation: '%s' ", target.description)

        if not dry_run:
            move_antennas(ants, azim, elev)

    user_logger.info("Sequence Completed!")
Example #6
0
def stow_test(ants, taz, tel, dry_run=False):

    # send this target to the antenna.
    target = katpoint.Target('Name, azel, %s, %s' % (taz, tel))

    if not dry_run:
        # Use slew to bypass pointing model
        ants.req.ap_slew(taz, tel)
        # Since we are not using the proxy mode we will have to explicitly wait
        # for the servo brakes to open and on-target sensor to update.
        time.sleep(4)

    user_logger.info("Starting target description: '%s' ", target.description)

    if not dry_run:
        try:
            ants.wait('ap.on-target', True, timeout=300)
            time.sleep(2)  # Track for a bit to allow deacceleration
        except:
            user_logger.error("Timed out while waiting for AP to reach "
                              "starting position.")
            raise

        user_logger.info("AP has reached start position, beginning stow test")

        user_logger.info("Activating receptor windstows")
        ants.req.set_windstow(1)
        ants.wait('ap.mode', 'stowed', timeout=120)

        # Wait a bit before clearing
        user_logger.info("Stow position reached. Monitoring for 20 seconds.")
        time.sleep(20)
        user_logger.info("Clearing receptor windstow condition")
        ants.req.set_windstow(0)
        ants.wait('mode', 'STOP', timeout=120)

        # Wait a bit and issue the windstow again to simulate wind picking up
        user_logger.info("Waiting 30 seconds before next 'gust'.")
        time.sleep(30)
        user_logger.info("Triggering 2nd windstow event.")
        ants.req.set_windstow(1)
        ants.wait('mode', 'STOW', timeout=120)

        user_logger.info("Montitoring for 20 seconds")
        # Reduced this time since we should already be up at stow position
        time.sleep(20)

        user_logger.info("Test concluded. Clearing windstow.")
        # Restore system to normal
        ants.req.set_windstow(0)
        ants.wait('mode', 'STOP', timeout=120)
Example #7
0
 def __exit__(self, exc_type, exc_value, traceback):
     """Exit the data capturing session, stopping the capture."""
     if exc_value is not None:
         exc_msg = str(exc_value)
         msg = "Session interrupted by exception (%s%s)" % \
               (exc_value.__class__.__name__,
                (": '%s'" % (exc_msg,)) if exc_msg else '')
         if exc_type is KeyboardInterrupt:
             user_logger.warning(msg)
         else:
             user_logger.error(msg, exc_info=True)
     self.cbf.req.dbe_capture_stop(self.instrument)
     user_logger.info('beamformer stopped')
     # Suppress KeyboardInterrupt so as not to scare the lay user,
     # but allow other exceptions that occurred in the body of with-statement
     return exc_type is KeyboardInterrupt
Example #8
0
def point(ants, target, timeout=300):
    # send this target to the antenna.
    ants.req.target(target)
    ants.req.mode("POINT")
    user_logger.info("Slewing to target : %s" % (target, ))
    # wait for antennas to lock onto target
    ants.set_sampling_strategy("lock", "period 1.0")
    success = ants.wait("lock", True, timeout)
    if success:
        user_logger.info("Tracking Target : %s " % (target, ))
    else:
        failed = [client for client in success if not success[client]]
        msg = "Waiting for sensor 'lock' == True "
        # Report failure to user (including list of clients that failed)
        msg += "reached timeout of %.1f seconds. " % (timeout, )
        msg += "Clients %r failed." % (sorted(failed), )
        user_logger.error(msg)
    return success
Example #9
0
def move_to(ants, az, el):
    user_logger.info("Slewing to Az: '%s' El: '%s'", az, el)
    # Use slew to bypass pointing model
    ants.req.ap_slew(az, el)
    # Since we are not using the proxy mode we will have to explicitly wait
    # for the servo brakes to open and on-target sensor to update.
    time.sleep(4)

    try:
        ants.wait('ap.on-target', True, timeout=300)
        time.sleep(2)  # Track for a bit to allow deacceleration
        user_logger.info("Position reached...")
    except:
        user_logger.error("Timed out while waiting for AP to reach "
                          "requested position.")
        raise

    # Arbitrary pause before next movement
    time.sleep(10)
Example #10
0
 def __exit__(self, exc_type, exc_value, traceback):
     """Exit the data capturing session, closing all streams."""
     if exc_value is not None:
         exc_msg = str(exc_value)
         msg = "Session interrupted by exception (%s%s)" % \
               (exc_value.__class__.__name__,
                (": '%s'" % (exc_msg,)) if exc_msg else '')
         if exc_type is KeyboardInterrupt:
             user_logger.warning(msg)
         else:
             user_logger.error(msg, exc_info=True)
     self.capture_stop()
     # Suppress KeyboardInterrupt so as not to scare the lay user,
     # but allow other exceptions that occurred in the body of with-statement
     if exc_type is KeyboardInterrupt:
         report_compact_traceback(traceback)
         return True
     else:
         return False
Example #11
0
def move_ri(ants, ridx_pos, dry_run=False):
    if ridx_pos not in ['u', 'l', 's', 'x']:
        raise ValueError("indexer position {} does not exist. active bands are 'u', 'l', 's', and 'x'".format(ridx_pos))
    user_logger.info("Moving receiver indexers to '{}' position".format(ridx_pos))
    ants.set_sampling_strategy("ap.ridx-brakes-released","period 0.5")
    ants.req.ap_set_indexer_position(ridx_pos)
    time.sleep(10)
    if not dry_run:
        try:
            # Wait for indexer brakes to engage again
            ants.wait('ap.ridx-brakes-released', False, timeout=60)
            user_logger.info('{} position reached'.format(ridx_pos))
        except Exception:
            not_on_pos = []
            not_on_pos = [ant.name for ant in ants if ant.sensor.ap_indexer_position.get_value() != ridx_pos]
            user_logger.error("Indexer brakes did not engage on: {}".format(', '.join(not_on_pos)))
        finally:
            # allow brakes to engage and put antennas to stop
            time.sleep(3)
            ants.req.mode('STOP')
            time.sleep(2)
Example #12
0
def report_sensors(kat, filter, status):
    user_logger.info("Requesting sensor values... (filter={}, status={})"
                     "".format(filter, status))
    sensors = kat.list_sensors(filter=filter)
    for s in sensors:
        try:
            sensor_obj = getattr(kat.sensor, escape_name(s[1]))
            sensor_obj.get_value()
        except:
            user_logger.error('Could not get the sensor value for {}'.format(
                s.name))
    user_logger.info("Waiting...")
    for i in range(0, len(sensors) / 20 + 1):
        time.sleep(0.1)

    sensors = kat.list_sensors(filter=filter, status=status)
    for s in sensors:
        name = s.name
        reading = s.reading
        val = str(reading.value)
        valTime = reading.received_timestamp
        updateTime = reading.timestamp
        stat = reading.status
        colour = get_sensor_colour(stat)
        # Print status with stratchar prefix - indicates strategy has been set
        val = val if len(
            val
        ) <= 45 else val[:42] + "..."  # truncate value to first 45 character
        val = r"\n".join(val.splitlines())
        user_logger.info("{} {} {} {} {}"
                         "".format(
                             col(colour) + name.ljust(45),
                             str(stat).ljust(15),
                             get_time_str(valTime).ljust(15),
                             get_time_str(updateTime).ljust(15),
                             str(val).ljust(45) + col('normal')))
Example #13
0
        )
    else:
        # Start capture session, which creates HDF5 file
        with start_session(kat, **vars(opts)) as session:
            user_logger.info("Setting up the signal Generator ip:port %s:%i." %
                             (siggen_ip, siggen_port))
            if not kat.dry_run or opts.force_siggen:  # prevent verifiing script from messing with things and failing to connect
                sigconn = SCPI.SCPI(siggen_ip, siggen_port)
                testcon = sigconn.testConnect()
            else:
                sigconn = Temp()
                testcon = False

            with sigconn as sig:
                if testcon == False:
                    user_logger.error(
                        'Test connection to signal generator failed.')
                else:
                    user_logger.info("Connected to Signal Generator:%s" %
                                     (testcon))
                    sig.reset()
                    user_logger.info("Signal Generator reset")
                    sig.outputOn()
                    user_logger.info("Signal Generator output on")
                    sig.setFrequency((siggen_freq + siggen_freq_minor) * 1.0e6)
                    user_logger.info(
                        "Signal Generator frequency is set to %7.3f MHz" %
                        (sig.getFrequency() * 1.0e-6))
                    siggen_freq = sig.getFrequency()
                    sig.setPower(siggen_power)
                    user_logger.info(
                        "Signal Generator Power is set to %f dBm" %
Example #14
0
                     if atten < 32 and (voltage > adc_volt + 20):  # Up
                         user_logger.info(
                             "'%s' band %s %s: Changing attenuation from %idB to %idB "
                             % (band, ant.name, pol, atten, atten + 1))
                         ant.req.dig_attenuation(pol, atten + 1)
                         ant_update[i] = True
                     if atten > 0 and (voltage < adc_volt
                                       or std < adc_std_in):
                         user_logger.info(
                             "'%s' band %s %s: Changing attenuation from %idB to %idB "
                             % (band, ant.name, pol, atten, atten - 1))
                         ant.req.dig_attenuation(pol, atten - 1)
                         ant_update[i] = True
             else:
                 user_logger.error(
                     "'%s' band %s %s band is not in the list of valid bands "
                     % (band, ant.name, pol))
 lines = []
 summary = []
 atten_ref = {}
 ant_list = []
 lines.append('Changing attenuation , report of refine_attenuation.py')
 for ant in kat.ants:
     band = get_ant_band(ant)
     if band in bandlist:
         ant_list.append(ant.name)
         for pol in {'h', 'v'}:
             std, atten, voltage = sample_bits(ant, pol, band=band)
             lines.append("'%s' band %s %s: ,%i #  std:%f   vol:%f" %
                          (band, ant.name, pol, atten, std, voltage))
             atten_ref['%s_%s' % (ant.name, pol)] = [
     for ant, value_h, value_v in tmp_data:
         try:
             atten_ref['%s_%s_%s' % (band, ant, 'h')] = np.int(value_h)
             atten_ref['%s_%s_%s' % (band, ant, 'v')] = np.int(value_v)
         except ValueError:
             user_logger.warning(
                 "'%s' band  %s: attenuation value '%s','%s' is not an integer "
                 % (band, ant, value_h, value_v))
 if not kat.dry_run:
     for pol in {'h', 'v'}:
         for ant in kat.ants:  # note ant is an katcp antenna object
             band = get_ant_band(ant)
             key_lookup = '%s_%s_%s' % (band, ant.name, pol)
             if key_lookup not in atten_ref:
                 user_logger.error(
                     "'%s' band %s %s: Has no attenuation value in the file "
                     % (band, ant.name, pol))
                 continue
             atten = measure_atten(ant,
                                   pol,
                                   atten_ref=atten_ref[key_lookup],
                                   band=band)
             if atten != atten_ref[key_lookup]:
                 user_logger.info(
                     "'%s' band %s %s: Changing attenuation from %idB to %idB "
                     % (band, ant.name, pol, atten, atten_ref[key_lookup]))
                 ant.req.dig_attenuation(pol, atten_ref[key_lookup])
         user_logger.info("Sleeping for 30 seconds ")
         time.sleep(30)
         # The sleep is because there is a potential +/-30sec loop in the
         # state machine in the digitiser and sending a second command
    kat.ants.set_sampling_strategy("ap.enable-point-error-tiltmeter", "event")

    if not kat.ants.req.mode('STOP'):
        user_logger.info("Setting antennas to mode 'STOP'")
        time.sleep(2)
    else:
        raise RuntimeError("Unable to set antennas to mode 'STOP'!")

    try:
        test_sequence(kat.ants,
                      disable_corrections=opts.no_corrections,
                      dry_run=kat.dry_run)
    finally:
        # Restore ACU pointing corrections
        kat.ants.req.ap_enable_point_error_systematic(False)
        kat.ants.req.ap_enable_point_error_tiltmeter(True)
        if not kat.dry_run:
            try:
                kat.ants.wait('ap.enable-point-error-systematic',
                              False,
                              timeout=1)
                kat.ants.wait('ap.enable-point-error-tiltmeter',
                              True,
                              timeout=1)
            except:
                user_logger.error("Failed to reset ACU pointing corrections.")
                raise

        kat.ants.req.mode('STOP')
        user_logger.info("Stopping antennas")
Example #17
0
#if len(args) == 0:
#    raise ValueError("Please specify the sources to observe as arguments, either as "
#                     "description strings or catalogue filenames")
fl = '/../2.1-Tipping_Curve/TBGAL_CONVL.FITS'
hdulist = pyfits.open(fl)
Data = np.flipud(np.fliplr(
    hdulist[0].data))  # data is in the first element of the fits file
ra = lambda x: int(x / 0.25)  # helper functions
dec = lambda x: int((-x + 90) / 0.25)

with verify_and_connect(opts) as kat:
    if not kat.dry_run and kat.ants.req.mode('STOP'):
        user_logger.info(
            "Setting Antenna Mode to 'STOP', Powering on Antenna Drives.")
    else:
        user_logger.error("Unable to set Antenna mode to 'STOP'.")
    moon = kat.sources.lookup['moon']
    with start_session(kat, **vars(opts)) as session:
        if not opts.no_delays and not kat.dry_run:
            if session.dbe.req.auto_delay('on'):
                user_logger.info("Turning on delay tracking.")
            else:
                user_logger.error('Unable to turn on delay tracking.')
        elif opts.no_delays and not kat.dry_run:
            if session.dbe.req.auto_delay('off'):
                user_logger.info("Turning off delay tracking.")
            else:
                user_logger.error('Unable to turn off delay tracking.')
            if session.dbe.req.zero_delay():
                user_logger.info("Zeroed the delay values.")
            else:
Example #18
0
def _set_dig_nd_(kat, timestamp, nd_setup=None, switch=0, cycle=False):
    """Setting and implementing digitiser noise diode command
    Parameters
    ----------
    kat : session kat container-like object
        Container for accessing KATCP resources allocated to schedule block.
    timestamp : float
        Linux timestamp in seconds at which to switch noise diode
    nd_setup : dict, optional (default = None, no pattern set)
        Noise diode pattern setup, with keys:
            'antennas':  options are 'all', or 'm062', or ....,
            'cycle_len': the cycle length [sec],
                           - must be less than 20 sec for L-band,
            etc., etc.
    switch : 0 or 1, optional (default = 0)
        Switch all noise diodes off (0) or on (1)

    Returns
    -------
    timestamp : float
        Linux timestamp reported by digitiser
    """

    if nd_setup is not None:
        # selected antennas for nd pattern
        nd_antennas = sorted(nd_setup['antennas'].split(","))
        # nd pattern length [sec]
        cycle_length = nd_setup['cycle_len']
        # on fraction of pattern length [%]
        on_fraction = nd_setup['on_frac']
        msg = ('Repeat noise diode pattern every {} sec, '
               'with {} sec on and apply pattern to {}'.format(
                   cycle_length,
                   float(cycle_length) * float(on_fraction), nd_antennas))
        user_logger.info(msg)
    else:
        nd_antennas = sorted(ant.name for ant in kat.ants)
        cycle_length = 1.
        on_fraction = switch

    # Noise diodes trigger is evaluated per antenna
    replies = {}
    for ant in nd_antennas:
        ped = getattr(kat, ant)
        # The digitiser master controller takes about 15-50 ms per request,
        # so start panicking just before the deadline.
        if time.time() > timestamp - 0.02:
            user_logger.error(
                'Requested noise diode timestamp %sZ will probably '
                'be in the past - please increase lead time',
                katpoint.Timestamp(timestamp))
            skipped = ','.join(nd_antennas[len(replies):])
            user_logger.error('Skipped setting these noise diodes: %s',
                              skipped)
            break
        replies[ant] = ped.req.dig_noise_source(timestamp, on_fraction,
                                                cycle_length)
        if kat.dry_run:
            msg = ('Dry-run: Set noise diode for antenna {} at '
                   'timestamp {}'.format(ant, timestamp))
            user_logger.debug(msg)
        if cycle:
            # add time [sec] to ensure all digitisers set at the same time
            timestamp += cycle_length * on_fraction

    # assuming ND for all antennas must be the same
    # only display single timestamp
    if not kat.dry_run:
        timestamp = _katcp_reply_(replies)
        # test incorrect reply check
        if len(replies) < len(nd_antennas):
            user_logger.error('Noise diode activation not in sync')
    if np.isfinite(timestamp):
        msg = (
            'Set successful noise diodes with average timestamp {:.0f} ({}Z)'.
            format(timestamp, katpoint.Timestamp(timestamp)))
        user_logger.debug('DEBUG: {}'.format(msg))

    return timestamp
Example #19
0
def track(ant, taz, tel, total=1, dry_run=False):

    # Direction variable ie. up/down, clockwise/anti-clockwise
    h_direction = 1
    v_direction = 1

    # Number of cycles done
    cycle_count = 0

    # Total number of degrees travelled in each axis
    az_total_angle = 0
    el_total_angle = 0

    #Total number of each type of slew completed
    az_7_deg_slews = 0
    el_7_deg_slews = 0
    az_26_deg_slews = 0
    el_23_deg_slews = 0

    # send this target to the antenna.
    target = katpoint.Target('Name, azel, %s, %s' % (taz, tel))

    if not dry_run:
        # Use slew to bypass pointing model
        ant.req.ap_slew(taz, tel)
        # Since we are not using the proxy mode we will have to explicitly wait
        # for the servo brakes to open and on-target sensor to update.
        time.sleep(4)

    user_logger.info("Starting target description: '%s' ", target.description)

    if not dry_run:
        try:
            ant.wait('ap.on-target', True, timeout=300)
            time.sleep(2)  # Track for a bit to allow deacceleration
        except:
            user_logger.error(
                "Timed out while waiting for AP to reach starting position.")
            raise

    user_logger.info(
        "AP has reached start position, beginning endurance cycle")
    if not dry_run:
        last_az = ant.sensor.ap_actual_azim.get_value()
        last_el = ant.sensor.ap_actual_elev.get_value()
    else:
        last_az = -135
        last_el = 15

    while cycle_count <= total:
        # Cycle loop
        # Azimuth cycle is 7, 26, 7 degrees
        # Elevation cycle is 7, 23.5, 7 degrees
        # Azel = [(7,7),(26,23.5),(7,7)]
        for az_offset, el_offset in [(7, 7), (26, 23), (7, 7)]:
            taz += az_offset * h_direction  # Find new coordinate based on current position
            tel += el_offset * v_direction

            # send this target to the antenna.
            target = katpoint.Target('Name, azel, %s, %s' % (taz, tel))

            if not dry_run:
                # Use slew to bypass pointing model
                ant.req.ap_slew(taz, tel)
                # Since we are not using the proxy mode we will have to explicitly wait
                # for the servo brakes to open and on-target sensor to update.
                time.sleep(4)

            user_logger.info("Target description: '%s' ( %s degree slew )",
                             target.description, str(az_offset))

            if not dry_run:
                try:
                    ant.wait('ap.on-target', True, timeout=300)
                    time.sleep(2)  # Track for a bit to allow deacceleration
                except:
                    user_logger.error(
                        "Timed out while waiting for AP to complete a slew.")
                    user_logger.info("7 deg slews: az - '%s', el - '%s' ",
                                     az_7_deg_slews, el_7_deg_slews)
                    user_logger.info("26/23 deg slews: az - '%s', el - '%s' ",
                                     az_26_deg_slews, el_23_deg_slews)
                    user_logger.info(
                        "Total degrees travelled: az - '%s', el - '%s' ",
                        az_total_angle, el_total_angle)
                    raise

            # Get the current position
            if not dry_run:
                current_az = ant.sensor.ap_actual_azim.get_value()
                current_el = ant.sensor.ap_actual_elev.get_value()
            else:
                current_az = -135
                current_el = 15

            # Add the angle travelled to the accumulated value
            az_total_angle += abs(current_az - last_az)
            el_total_angle += abs(current_el - last_el)

            # Update last_<axis> values
            last_az = current_az
            last_el = current_el

            if az_offset == 7:
                az_7_deg_slews += 1
            else:
                az_26_deg_slews += 1
            if el_offset == 7:
                el_7_deg_slews += 1
            else:
                el_23_deg_slews += 1

        # Update cycle counter
        cycle_count += 1
        # If we have done 2 elevation cycles then reverse direction
        if cycle_count % 2 == 0:
            v_direction = v_direction * -1
        # If we have done 9 azimuth cycles then reverse direction
        if cycle_count % 9 == 0:
            h_direction = h_direction * -1

        # Only need this bit if we are not doing indexer test
        #if not dry_run:
        #   time.sleep(228)

        if not dry_run:
            ant.req.mode('STOP')
            # Add a sleep since the indexer portion of the script
            # does not use the waiting functionality that is part
            # of the receptor proxy mode requests
            time.sleep(3)

        # NOTE: Using the indexer positioning time spec as we are more
        #       concerned with repetitions than accuracy for this test.
        indexer_timeout = 60
        # Position raw changed after indexer configurations
        ridx_angle = {'s': -0.618, 'l': 39.248, 'x': 79.143, 'u': 119.405}
        ridx_sequence = ['s', 'l', 'x', 'u']

        # TODO: Revisit this once we have more information from AP team
        #       about indexer drift issues
        if not dry_run:
            # If we are closer to 'u' than 's', then start from 'u' instead
            if ant.sensor.ap_indexer_position_raw.get_value() > 60:
                ridx_sequence.reverse()

            ridx_last_position = ant.sensor.ap_indexer_position.get_value()
        else:
            ridx_last_position = None

        # NOTE: we skip the first position in the list if we are already
        #       there because the indexer seems to end up in a 'moving'
        #       state after a few cycles of operating the drive. Revisit
        #       this after feedback from Nico
        if ridx_last_position == ridx_sequence[0]:
            ridx_sequence = ridx_sequence[1:]

        if not dry_run:
            for pos in ridx_sequence:

                ridx_movement_start_time = time.time()
                user_logger.info("--- Moving RI to position: '%s' ---",
                                 pos.upper())
                ant.req.ap_set_indexer_position(pos)

                # TODO: Add a promximity check for S position in case this increased
                #       sleep still does not help
                # Wait for indexer brakes to open
                time.sleep(3)
                try:
                    # Wait for indexer brakes to engage again
                    ant.wait('ap.ridx-brakes-released',
                             False,
                             timeout=indexer_timeout)
                except:
                    user_logger.error("Indexer brakes did not engage "
                                      "(hunting issue). Giving up and "
                                      "trying the next position.")
                    ant.req.mode('STOP')
                    time.sleep(3)
                    # NOTE: We do not raise the timeout exception as we want
                    #       to try to continue.

                # Wait for power to encoder to switch off
                time.sleep(5)

                ridx_current_position = ant.sensors.ap_indexer_position.get_value(
                )
                time_to_index = time.time() - ridx_movement_start_time

                ridx_position_raw = ant.sensor.ap_indexer_position_raw.get_value(
                )
                ridx_brakes_released = ant.sensor.ap_ridx_brakes_released.get_value(
                )
                if ridx_current_position != pos:

                    user_logger.error(
                        "Indexer error after %s seconds! "
                        "Requested position: '%s'. "
                        "Current position: '%s'. "
                        "Encoder reading is %s degrees. "
                        "Position error: %.6f degrees. "
                        "Brakes released: '%s'. ", time_to_index, pos.upper(),
                        ridx_current_position, ridx_position_raw,
                        abs(ridx_angle[pos] - ridx_position_raw),
                        ridx_brakes_released)

                    # NOTE: We ignore the failed check here for now and
                    #       continue the script by not raising an exception.
                else:
                    user_logger.info(
                        "Brake engaged. The offset from the requested position: "
                        "'%s' is %.6f degree(s)", pos.upper(),
                        abs(ridx_angle[pos] - ridx_position_raw))
                    user_logger.info(
                        "Request for angle '%s' to final angle '%s' "
                        "took '%s' seconds.", ridx_angle[pos],
                        ridx_position_raw, time_to_index)

                # Wait a little before requesting next indexer position
                time.sleep(5)

    # Print out slew numbers once all cycles are completed
    user_logger.info("7 deg slews: az - '%s', el - '%s' ", az_7_deg_slews,
                     el_7_deg_slews)
    user_logger.info("26/23 deg slews: az - '%s', el - '%s' ", az_26_deg_slews,
                     el_23_deg_slews)
    user_logger.info("Total degrees travelled: az - '%s', el - '%s' ",
                     az_total_angle, el_total_angle)
Example #20
0
def reversescan(session, target, nd_period=None, lead_time=None, **kwargs):
    """Reverse scan observation.

    This scan is done in "Reverse"
    This means that it is given an area to scan (via kwargs)
    rather that a target and parameters

    Parameters
    ----------
    session: `CaptureSession`
    target: katpoint.Target
    nd_period: float
        noisediode period
    lead_time: float
        noisediode trigger lead time

    """
    # trigger noise diode if set
    trigger(session.kat, duration=nd_period, lead_time=lead_time)
    if 'radec_p1' in kwargs and 'radec_p2' in kwargs:
        # means that there is a target area
        # find lowest setting part or
        # highest rising part
        antenna = copy.copy(target.antenna)
        target_list = []
        for i in range(1, _MAX_POINTS_IN_SCAN_AREA_POLYGON + 1):
            key = 'radec_p%i' % i
            if key in kwargs:
                target_list.append(
                    katpoint.Target(
                        't%i,radec,%s' % (i, kwargs[key]),
                        antenna=target.antenna,
                    ))
    else:
        user_logger.error(
            "No scan area defined - require radec_p1 and radec_p2")
        return False
    direction = kwargs.get("direction", False)
    scan_speed = kwargs.get("scan_speed", _DEFAULT_SCAN_SPEED_ARCMIN_PER_SEC)

    obs_start_ts = katpoint.Timestamp(time.time()).to_ephem_date()
    # use 1 deg offset to pre-position >4 min in the future to take into account slewing
    el, az_min, az_max, t_start, t_end = _get_scan_area_extents(target_list,
                                                                antenna,
                                                                obs_start_ts,
                                                                offset_deg=1)

    # TODO: get horizon limit from observation - may want to pass limits of
    #       the "acceptable elevation extent" into _get_scan_area_extents.
    if _MIN_HORIZON_EL_FOR_SCAN_DEG > np.degrees(el):
        user_logger.warning(
            "Source and scan below horizon: %s < %s",
            np.degrees(el),
            _MIN_HORIZON_EL_FOR_SCAN_DEG,
        )
        return False

    scan_target = katpoint.construct_azel_target(katpoint.wrap_angle(az_min),
                                                 el)
    scan_target.name = target.name
    # katpoint destructively set dates and times during calculation
    # restore datetime before continuing
    scan_target.antenna = antenna
    scan_target.antenna.observer.date = obs_start_ts
    user_logger.info("Slew to scan start")  # slew to target.
    target_visible = session.track(scan_target, duration=0.0, announce=False)
    if not target_visible:
        user_logger.warning(
            "Start of scan is not visible!  Elevation: %.1f deg.",
            np.degrees(el))
        return False

    # This is the real scan
    obs_start_ts = katpoint.Timestamp(time.time()).to_ephem_date()
    el, az_min, az_max, t_start, t_end = _get_scan_area_extents(
        target_list, antenna, obs_start_ts)
    scan_target = katpoint.construct_azel_target(
        katpoint.wrap_angle((az_min + az_max) / 2.), el)
    scan_target.name = target.name
    # katpoint destructively set dates and times during calculation
    # restore datetime before continuing
    scan_target.antenna = antenna
    scan_target.antenna.observer.date = obs_start_ts

    scan_start = np.degrees(az_min - (az_min + az_max) / 2.)
    scan_end = np.degrees(az_max - (az_min + az_max) / 2.)

    scanargs = {}
    if "projection" in kwargs:
        scanargs["projection"] = kwargs["projection"]

    # take into account projection effects of the sky and convert to degrees per second
    # E.g., 5 arcmin/s should translate to 5/60/cos(el) deg/s
    scan_speed = (scan_speed / 60.0) / np.cos(el)
    scanargs["duration"] = abs(scan_start -
                               scan_end) / scan_speed  # Duration in seconds
    user_logger.info("Scan duration is %.2f and scan speed is %.2f deg/s",
                     scanargs["duration"], scan_speed)
    user_logger.info("Start Time: %s", t_start)
    user_logger.info("End Time: %s", t_end)
    num_scan_lines = 0
    while time.time() <= t_end.secs:
        if direction:
            scanargs["start"] = scan_start, 0.0
            scanargs["end"] = scan_end, 0.0
        else:
            scanargs["start"] = scan_end, 0.0
            scanargs["end"] = scan_start, 0.0
        user_logger.info("Azimuth scan extent [%.1f, %.1f]" %
                         (scanargs["start"][0], scanargs["end"][0]))
        target_visible = scan(session,
                              scan_target,
                              nd_period=nd_period,
                              lead_time=lead_time,
                              **scanargs)
        direction = not direction
        if target_visible:
            num_scan_lines += 1
    user_logger.info("Scan completed - %s scan lines", num_scan_lines)
    return num_scan_lines > 0
Example #21
0
def pattern(kat,
            nd_setup,
            lead_time=_DEFAULT_LEAD_TIME,
            ):
    """Start background noise diode pattern controlled by digitiser hardware.

    Parameters
    ----------
    kat : session kat container-like object
        Container for accessing KATCP resources allocated to schedule block.
    nd_setup : dict
        Noise diode pattern setup, with keys:
            'antennas':  options are 'all', or 'm062', or ....,
            'cycle_len': the cycle length [sec],
                           - must be less than 20 sec for L-band,
            etc., etc.
    lead_time : float, optional (default = system default lead time)
        Lead time before digitisers pattern is set [sec]

    Returns
    -------
    timestamp : float
        Linux timestamp reported by digitiser
    """

    # nd pattern length [sec]
    max_cycle_len = _get_max_cycle_len(kat)
    if float(nd_setup['cycle_len']) > max_cycle_len:
        msg = 'Maximum cycle length is {} seconds'.format(max_cycle_len)
        raise RuntimeError(msg)

    user_logger.trace('TRACE: max cycle len {}'
                      .format(max_cycle_len))

    # Try to trigger noise diodes on specified antennas in array simultaneously.
    # - add a default lead time to ensure enough time for all digitisers
    #   to be set up
    if lead_time >= max_cycle_len:
        user_logger.error('Nonstandard ND usage: lead time > max cycle len')
        raise RuntimeError('ND pattern setting cannot be achieved')

    start_time = _get_nd_timestamp_(lead_time)
    user_logger.trace('TRACE: desired start_time {} ({})'
                      .format(start_time,
                              time.ctime(start_time)))
    msg = ('Request: Set noise diode pattern to activate at {} '
           '(includes {} sec lead time)'
           .format(start_time,
                   lead_time))
    user_logger.warning(msg)

    nd_antennas = nd_setup['antennas']
    sb_ants = ",".join(str(ant.name) for ant in kat.ants)
    nd_setup['antennas'] = sb_ants
    if nd_antennas == 'all':
        cycle = False
    elif nd_antennas == 'cycle':
        cycle = True
    else:
        cycle = False
        nd_setup['antennas'] = ",".join(
            ant.strip() for ant in nd_antennas.split(",") if ant.strip() in sb_ants
        )
    user_logger.info('Antennas found in subarray, setting ND: {}'
                     .format(nd_setup['antennas']))

    # Noise Diodes are triggered simultaneously
    # on specified antennas in the array
    timestamp = _set_dig_nd_(kat,
                             start_time,
                             nd_setup=nd_setup,
                             cycle=cycle)
    user_logger.trace('TRACE: now {} ({})'
                      .format(time.time(),
                              time.ctime(time.time())))
    user_logger.trace('TRACE: timestamp {} ({})'
                      .format(timestamp,
                              time.ctime(timestamp)))
    wait_time = timestamp - time.time()
    user_logger.trace('TRACE: delta {}'
                      .format(wait_time))
    time.sleep(wait_time)
    user_logger.trace('TRACE: set nd pattern at {}, slept {}'
                      .format(time.time(),
                              wait_time))
    msg = ('Report: Switch noise-diode pattern on at {}'
           .format(timestamp))
    user_logger.info(msg)
    return timestamp
Example #22
0
    kind=opts.kind,
    mirrorx=opts.mirrorx)
timeperstep = opts.sampletime

if len(args) == 0:
    raise ValueError(
        "Please specify a target argument via name ('Ori A'), "
        "description ('azel, 20, 30') or catalogue file name ('sources.csv')")

# Check basic command-line options and obtain a kat object connected to the appropriate system
with verify_and_connect(opts) as kat:
    if not kat.dry_run and kat.ants.req.mode('STOP'):
        user_logger.info(
            "Setting Antenna Mode to 'STOP', Powering on Antenna Drives.")
    else:
        user_logger.error("Unable to set Antenna mode to 'STOP'.")
    catalogue = collect_targets(kat, args)
    targets = catalogue.targets
    if len(targets) == 0:
        raise ValueError(
            "Please specify a target argument via name ('Ori A'), "
            "description ('azel, 20, 30') or catalogue file name ('sources.csv')"
        )
    target = targets[0]  #only use first target
    lasttargetel = target.azel()[1] * 180.0 / np.pi

    # Initialise a capturing session (which typically opens an HDF5 file)
    with start_session(kat, **vars(opts)) as session:
        # Use the command-line options to set up the system
        session.standard_setup(**vars(opts))
        if not opts.no_delays and not kat.dry_run:
Example #23
0
def rate_slew(ants,
              azim,
              elev,
              speed=0.5,
              reverse=False,
              disable_corrections=False,
              dry_run=False):

    # Scale timeout with requested test speed. Full speed timeout is 5 min
    rate_timeout = (float(2) / speed) * 300
    # Only testing movement in azimuth, not elevation
    azim_speed = speed
    elev_speed = 0.0
    sensor_name = "ap.actual-azim"
    # Only testing 365 degrees, not full travel range (460 degrees)
    expected_azim = (azim + 365.0 if speed > 0 else azim - 365.0)
    # Position threshold 2 degrees to catch it at 0.5 second polling
    # period at full speed (2 deg/sec).
    threshold = 2

    if (-185.0 < expected_azim < 275.0):
        user_logger.info("Antennas will perform a rate slew to azimuth %s",
                         expected_azim)
    else:
        raise ParametersExceedTravelRange("Cannot perform 365 degree slew "
                                          "within the AP azim travel range "
                                          "from the given start position.")

    # Set this target for the receptor target sensor
    target = katpoint.Target('Name, azel, %s, %s' % (azim, elev))

    if not dry_run:
        # Use slew to bypass pointing model
        ants.req.ap_slew(azim, elev)
        # Since we are not using the proxy request we will have to explicitly
        # wait for the servo brakes to open and on-target sensor to update.
        time.sleep(4)

    user_logger.info("Starting target description: '%s' ", target.description)

    if not dry_run:
        try:
            ants.wait('ap.on-target', True, timeout=300)
            time.sleep(2)  # Track for a bit to allow deacceleration
        except:
            user_logger.error(
                "Timed out while waiting for AP to reach starting position.")
            raise

    user_logger.info("AP has reached start position.")

    if not dry_run:
        if disable_corrections:
            SPEM_state = False  # np.any([a.sensors.ap_point_error_systematic_enabled.get_value() for a in ants]) # TODO finalize the commented-out snippet
            TILT_state = True  # np.any([a.sensors.ap_point_error_tiltmeter_enabled.get_value() for a in ants])
            ants.req.ap_enable_point_error_systematic(False)
            ants.req.ap_enable_point_error_tiltmeter(False)

        ants.req.mode('STOP')
        time.sleep(3)

        ants.req.ap_rate(azim_speed, elev_speed)
        user_logger.info("Performing rate slew to azimuth %s at %s deg/sec.",
                         expected_azim, azim_speed)
        # Wait until we are within a threshold of the expected ending azimuth
        ants.wait(sensor_name,
                  lambda c: abs(c.value - expected_azim) < threshold,
                  timeout=rate_timeout)

        if reverse:
            user_logger.info("Reverse slew selected...")
            ants.req.mode('STOP')
            time.sleep(8)
            ants.req.ap_rate(-1 * azim_speed, elev_speed)
            user_logger.info(
                "Performing rate slew to azimuth %s at %s deg/sec.", azim,
                azim_speed)
            # Head back to the starting azim that was passed into the function
            ants.wait(sensor_name,
                      lambda c: abs(c.value - azim) < threshold,
                      timeout=rate_timeout)

        if disable_corrections:
            ants.req.ap_enable_point_error_systematic(SPEM_state)
            ants.req.ap_enable_point_error_tiltmeter(TILT_state)

    user_logger.info("Sequence Completed!")
Example #24
0
            off1.name = 'off1'

            off2_azel = katpoint.construct_azel_target(wrap_angle(moon.azel()[0] - np.radians(10)),
                                                       moon.azel()[1])
            off2_azel.antenna = antenna
            off2 = katpoint.construct_radec_target(off2_azel.radec()[0], off2_azel.radec()[1])
            off2.antenna = antenna
            off2.name = 'off2'
            sources = katpoint.Catalogue(add_specials=False)
            sources.add(moon)
            sources.add(off2)
            sources.add(off1)
            txtlist = ', '.join(["'%s'" % (target.name,) for target in sources])
            user_logger.info("Calibration targets are [%s]", txtlist)
            for target in sources:
                session.nd_params = nd_off
                for nd in [nd_coupler]:
                    session.nd_params = nd_off
                    session.track(target, duration=0)  # get onto the source
                    user_logger.info("Now capturing data - diode %s on", nd['diode'])
                    session.label('%s' % (nd['diode'],))
                    if not session.fire_noise_diode(announce=True, **nd):
                        user_logger.error("Noise diode %s did not fire", nd['diode'])
                session.nd_params = nd_off
                user_logger.info("Now capturing data - noise diode off")
                session.label('track')
                session.track(target, duration=opts.track_duration)
        if opts.max_duration and time.time() > start_time + opts.max_duration:
            user_logger.info('Maximum script duration (%d s) exceeded, stopping script',
                             opts.max_duration)
Example #25
0
def _set_dig_nd_(kat,
                 timestamp,
                 nd_setup=None,
                 switch=0,
                 cycle=False):
    """Setting and implementing digitiser noise diode command
    Parameters
    ----------
    kat : session kat container-like object
        Container for accessing KATCP resources allocated to schedule block.
    timestamp : float
        Linux timestamp in seconds at which to switch noise diode
    nd_setup : dict, optional (default = None, no pattern set)
        Noise diode pattern setup, with keys:
            'antennas':  options are 'all', or 'm062', or ....,
            'cycle_len': the cycle length [sec],
                           - must be less than 20 sec for L-band,
            etc., etc.
    switch : 0 or 1, optional (default = 0)
        Switch all noise diodes off (0) or on (1)

    Returns
    -------
    timestamp : float
        Linux timestamp reported by digitiser
    """

    if nd_setup is not None:
        # selected antennas for nd pattern
        nd_antennas = sorted(nd_setup['antennas'].split(","))
        # nd pattern length [sec]
        cycle_length = nd_setup['cycle_len']
        # on fraction of pattern length [%]
        on_fraction = nd_setup['on_frac']
        msg = ('Repeat noise diode pattern every {} sec, '
               'with {} sec on and apply pattern to {}'
               .format(cycle_length,
                       float(cycle_length) * float(on_fraction),
                       nd_antennas))
        user_logger.info(msg)
    else:
        nd_antennas = sorted(ant.name for ant in kat.ants)
        cycle_length = 1.
        on_fraction = switch

    # Noise diodes trigger is evaluated per antenna
    timestamps = []
    for ant in nd_antennas:
        ped = getattr(kat, ant)
        reply = ped.req.dig_noise_source(timestamp,
                                         on_fraction,
                                         cycle_length)
        if not kat.dry_run:
            timestamps.append(_katcp_reply_({ant: reply}))
        else:
            msg = ('Dry-run: Set noise diode for antenna {} at '
                   'timestamp {}'.format(ant, timestamp))
            user_logger.debug(msg)

        if cycle:
            # add time [sec] to ensure all digitisers set at the same time
            timestamp += cycle_length * on_fraction

    # assuming ND for all antennas must be the same
    # only display single timestamp
    if not kat.dry_run:
        # test incorrect reply check
        if len(timestamps) < len(nd_antennas):
            err_msg = 'Noise diode activation not in sync'
            user_logger.error(err_msg)
        timestamp = np.mean(timestamps)
    msg = ('Set all noise diodes with timestamp {} ({})'
           .format(int(timestamp),
                   time.ctime(timestamp)))
    user_logger.debug('DEBUG: {}'.format(msg))

    return timestamp
Example #26
0
                                                   off2_azel.radec()[1])
            off2.antenna = antenna
            off2.name = 'off2'
            sources = katpoint.Catalogue(add_specials=False)
            sources.add(moon)
            sources.add(off2)
            sources.add(off1)
            txtlist = ', '.join(
                ["'%s'" % (target.name, ) for target in sources])
            user_logger.info("Calibration targets are [%s]" % (txtlist))
            for target in sources:
                session.nd_params = nd_off
                for nd in [nd_coupler]:
                    session.nd_params = nd_off
                    session.track(target, duration=0)  # get onto the source
                    user_logger.info("Now capturing data - diode %s on" %
                                     nd['diode'])
                    session.label('%s' % (nd['diode']))
                    if not session.fire_noise_diode(announce=True, **nd):
                        user_logger.error(
                            "Noise Diode did not Fire , (%s did not fire)" %
                            nd['diode'])
                session.nd_params = nd_off
                user_logger.info("Now capturing data - noise diode off")
                session.label('track')
                session.track(target, duration=opts.track_duration)
        if opts.max_duration and time.time() > start_time + opts.max_duration:
            user_logger.info(
                'Maximum script duration (%d s) exceeded, stopping script' %
                (opts.max_duration, ))
Example #27
0
def run_observation(opts, kat):
    """Extract control and observation information provided in observation file."""
    obs_plan_params = opts.obs_plan_params
    # remove observation specific instructions housed in YAML file
    del opts.obs_plan_params

    # set up duration periods for observation control
    obs_duration = -1
    if "durations" in obs_plan_params:
        if "obs_duration" in obs_plan_params["durations"]:
            obs_duration = obs_plan_params["durations"]["obs_duration"]
    # check for nonsensical observation duration setting
    if abs(obs_duration) < 1e-5:
        user_logger.error(
            "Unexpected value: obs_duration: {}".format(obs_duration))
        return

    # TODO: the description requirement in sessions should be re-evaluated
    # since the schedule block has the description
    # Description argument in instruction_set should be retired, but is
    # needed by sessions
    # Assign proposal_description if available, else create a dummy
    if "description" not in vars(opts):
        session_opts = vars(opts)
        description = "Observation run"
        if "proposal_description" in vars(opts):
            description = opts.proposal_description
        session_opts["description"] = description

    nr_obs_loops = len(obs_plan_params["observation_loop"])
    with start_session(kat.array, **vars(opts)) as session:
        session.standard_setup(**vars(opts))

        # Each observation loop contains a number of observation cycles over LST ranges
        # For a single observation loop, only a start LST and duration is required
        # Target observation loop
        observation_timer = time.time()
        for obs_cntr, observation_cycle in enumerate(
                obs_plan_params["observation_loop"]):
            if nr_obs_loops > 1:
                user_logger.info("Observation loop {} of {}.".format(
                    obs_cntr + 1, nr_obs_loops))
                user_logger.info("Loop LST range {}.".format(
                    observation_cycle["LST"]))
            # Unpack all target information
            if not ("target_list" in observation_cycle.keys()):
                user_logger.error(
                    "No targets provided - stopping script instead of hanging around"
                )
                continue
            obs_targets = observation_cycle["target_list"]
            target_list = obs_targets["target"].tolist()
            # build katpoint catalogues for tidy handling of targets
            catalogue = collect_targets(kat.array, target_list)
            obs_tags = []
            for tgt in obs_targets:
                # catalogue names are no longer unique
                name = tgt["name"]
                # add tag evaluation to identify catalogue targets
                tags = tgt["target"].split(",")[1].strip()
                for cat_tgt in catalogue:
                    if name == cat_tgt.name:
                        if ("special" in cat_tgt.tags
                                or "xephem" in cat_tgt.tags
                                or tags == " ".join(cat_tgt.tags)):
                            tgt["target"] = cat_tgt
                            obs_tags.extend(cat_tgt.tags)
                            break
            obs_tags = list(set(obs_tags))
            cal_tags = [tag for tag in obs_tags if tag[-3:] == "cal"]

            # observer object handle to track the observation timing in a more user
            # friendly way
            #             observer = catalogue._antenna.observer
            ref_antenna = catalogue.antenna
            observer = ref_antenna.observer
            start_datetime = timestamp2datetime(time.time())
            observer.date = ephem.Date(start_datetime)
            user_logger.trace("TRACE: requested start time "
                              "({}) {}".format(
                                  datetime2timestamp(start_datetime),
                                  start_datetime))
            user_logger.trace("TRACE: observer at start\n {}".format(observer))

            # Only observe targets in valid LST range
            if nr_obs_loops > 1 and obs_cntr < nr_obs_loops - 1:
                [start_lst, end_lst] = get_lst(observation_cycle["LST"],
                                               multi_loop=True)
                if end_lst is None:
                    # for multi loop the end lst is required
                    raise RuntimeError(
                        'Multi-loop observations require end LST times')
                next_obs_plan = obs_plan_params["observation_loop"][obs_cntr +
                                                                    1]
                [next_start_lst, next_end_lst] = get_lst(next_obs_plan["LST"])
                user_logger.trace("TRACE: current LST range {}-{}".format(
                    ephem.hours(str(start_lst)), ephem.hours(str(end_lst))))
                user_logger.trace("TRACE: next LST range {}-{}".format(
                    ephem.hours(str(next_start_lst)),
                    ephem.hours(str(next_end_lst))))
            else:
                next_start_lst = None
                next_end_lst = None
                [start_lst, end_lst] = get_lst(observation_cycle["LST"])

            # Verify the observation is in a valid LST range
            # and that it is worth while continuing with the observation
            # Do not use float() values, ephem.hours does not convert as
            # expected
            local_lst = observer.sidereal_time()
            user_logger.trace("TRACE: Local LST {}".format(
                ephem.hours(local_lst)))
            # Only observe targets in current LST range
            log_msg = "Local LST outside LST range {}-{}".format(
                ephem.hours(str(start_lst)), ephem.hours(str(end_lst)))
            if float(start_lst) < end_lst:
                # lst ends before midnight
                if not _same_day(start_lst, end_lst, local_lst):
                    if obs_cntr < nr_obs_loops - 1:
                        user_logger.info(log_msg)
                    else:
                        user_logger.error(log_msg)
                    continue
            else:
                # lst ends after midnight
                if _next_day(start_lst, end_lst, local_lst):
                    if obs_cntr < nr_obs_loops - 1:
                        user_logger.info(log_msg)
                    else:
                        user_logger.error(log_msg)
                    continue

            # Verify that it is worth while continuing with the observation
            # The filter functions uses the current time as timestamps
            # and thus incorrectly set the simulation timestamp
            if not kat.array.dry_run:
                # Quit early if there are no sources to observe
                if len(catalogue.filter(el_limit_deg=opts.horizon)) == 0:
                    raise NoTargetsUpError(
                        "No targets are currently visible - "
                        "please re-run the script later")
                # Quit early if the observation requires all targets to be visible
                if opts.all_up and (len(
                        catalogue.filter(el_limit_deg=opts.horizon)) !=
                                    len(catalogue)):
                    raise NotAllTargetsUpError(
                        "Not all targets are currently visible - please re-run the script"
                        "with --visibility for information")

            # List sources and their associated functions from observation tags
            not_cals_filter_list = []
            for cal_type in cal_tags:
                not_cals_filter_list.append("~{}".format(cal_type))
                cal_array = [cal.name for cal in catalogue.filter(cal_type)]
                if len(cal_array) < 1:
                    continue  # do not display empty tags
                user_logger.info("{} calibrators are {}".format(
                    str.upper(cal_type[:-3]), cal_array))
            user_logger.info("Observation targets are [{}]".format(", ".join([
                repr(target.name)
                for target in catalogue.filter(not_cals_filter_list)
            ])))

            # TODO: setup of noise diode pattern should be moved to sessions
            #  so it happens in the line above
            if "noise_diode" in obs_plan_params:
                nd_setup = obs_plan_params["noise_diode"]
                nd_lead = nd_setup.get('lead_time')

                # Set noise diode period to multiple of correlator integration time.
                if not kat.array.dry_run:
                    cbf_corr = session.cbf.correlator
                    dump_period = cbf_corr.sensor.int_time.get_value()
                else:
                    dump_period = 0.5  # sec
                user_logger.debug(
                    'DEBUG: Correlator integration time {} [sec]'.format(
                        dump_period))

                if "cycle_len" in nd_setup:
                    if (nd_setup['cycle_len'] >= dump_period):
                        cycle_len_frac = nd_setup['cycle_len'] // dump_period
                        nd_setup['cycle_len'] = cycle_len_frac * dump_period
                        msg = ('Set noise diode period '
                               'to multiple of correlator dump period: '
                               'cycle length = {} [sec]'.format(
                                   nd_setup['cycle_len']))
                    else:
                        msg = ('Requested cycle length {}s '
                               '< correlator dump period {}s, '
                               'ND not synchronised with dump edge'.format(
                                   nd_setup['cycle_len'], dump_period))
                    user_logger.warning(msg)
                    noisediode.pattern(
                        kat.array,
                        nd_setup,
                        lead_time=nd_lead,
                    )

            # Adding explicit init after "Capture-init failed" exception was
            # encountered
            session.capture_init()
            user_logger.debug("DEBUG: Initialise capture start with timestamp "
                              "{} ({})".format(int(time.time()),
                                               timestamp2datetime(
                                                   time.time())))

            # Go to first target before starting capture
            user_logger.info("Slewing to first target")
            observe(session, ref_antenna, obs_targets[0], slewonly=True)
            # Only start capturing once we are on target
            session.capture_start()
            user_logger.trace("TRACE: capture start time after slew "
                              "({}) {}".format(time.time(),
                                               timestamp2datetime(
                                                   time.time())))
            user_logger.trace(
                "TRACE: observer after slew\n {}".format(observer))

            done = False
            sanity_cntr = 0
            while not done:
                # small errors can cause an infinite loop here
                # preventing infinite loops
                sanity_cntr += 1
                if sanity_cntr > 100000:
                    user_logger.error("While limit counter has reached {}, "
                                      "exiting".format(sanity_cntr))
                    break

                # Cycle through target list in order listed
                targets_visible = False
                time_remaining = obs_duration
                observation_timer = time.time()
                for tgt_cntr, target in enumerate(obs_targets):
                    katpt_target = target["target"]
                    user_logger.debug("DEBUG: {} {}".format(tgt_cntr, target))
                    user_logger.trace(
                        "TRACE: initial observer for target\n {}".format(
                            observer))
                    # check target visible before doing anything
                    # make sure the target would be visible for the entire duration
                    target_duration = target['duration']
                    visible = True
                    if type(katpt_target.body) is ephem.FixedBody:
                        visible = above_horizon(
                            target=katpt_target.body.copy(),
                            observer=observer.copy(),
                            horizon=opts.horizon,
                            duration=target_duration)
                    if not visible:
                        show_horizon_status = True
                        # warning for cadence targets only when they are due
                        if (target["cadence"] > 0
                                and target["last_observed"] is not None):
                            delta_time = time.time() - target["last_observed"]
                            show_horizon_status = delta_time >= target[
                                "cadence"]
                        if show_horizon_status:
                            user_logger.warn("Target {} below {} deg horizon, "
                                             "continuing".format(
                                                 target["name"], opts.horizon))
                        continue
                    user_logger.trace(
                        "TRACE: observer after horizon check\n {}".format(
                            observer))

                    # check and observe all targets with cadences
                    while_cntr = 0
                    cadence_targets = list(obs_targets)
                    while True:
                        tgt = cadence_target(cadence_targets)
                        if not tgt:
                            break
                        # check enough time remaining to continue
                        if obs_duration > 0 and time_remaining < tgt[
                                "duration"]:
                            done = True
                            break
                        # check target visible before doing anything
                        user_logger.trace("TRACE: cadence"
                                          "target\n{}\n {}".format(
                                              tgt, catalogue[tgt["name"]]))
                        user_logger.trace("TRACE: initial observer for cadence"
                                          "target\n {}".format(observer))
                        user_logger.trace(
                            "TRACE: observer before track\n {}".format(
                                observer))
                        user_logger.trace(
                            "TRACE: target observation # {} last observed "
                            "{}".format(tgt["obs_cntr"], tgt["last_observed"]))
                        cat_target = catalogue[tgt["name"]]
                        if above_horizon(
                                target=cat_target.body,
                                observer=cat_target.antenna.observer.copy(),
                                horizon=opts.horizon,
                                duration=tgt["duration"]):
                            if observe(session, ref_antenna, tgt,
                                       **obs_plan_params):
                                targets_visible += True
                                tgt["obs_cntr"] += 1
                                tgt["last_observed"] = time.time()
                            else:
                                # target not visibile to sessions anymore
                                cadence_targets.remove(tgt)
                            user_logger.trace(
                                "TRACE: observer after track\n {}".format(
                                    observer))
                            user_logger.trace(
                                "TRACE: target observation # {} last observed "
                                "{}".format(tgt["obs_cntr"],
                                            tgt["last_observed"]))
                        else:
                            cadence_targets.remove(tgt)
                        while_cntr += 1
                        if while_cntr > len(obs_targets):
                            break
                    if done:
                        break
                    user_logger.trace(
                        "TRACE: observer after cadence\n {}".format(observer))

                    # observe non cadence target
                    if target["cadence"] < 0:
                        user_logger.trace(
                            "TRACE: normal target\n {}".format(target))
                        user_logger.trace(
                            "TRACE: observer before track\n {}".format(
                                observer))
                        user_logger.trace("TRACE: ts before observe {}".format(
                            time.time()))
                        user_logger.trace("TRACE: target last "
                                          "observed {}".format(
                                              target["last_observed"]))

                        targets_visible += observe(session, ref_antenna,
                                                   target, **obs_plan_params)
                        user_logger.trace(
                            "TRACE: observer after track\n {}".format(
                                observer))
                        user_logger.trace("TRACE: ts after observe {}".format(
                            time.time()))
                        if targets_visible:
                            target["obs_cntr"] += 1
                            target["last_observed"] = time.time()
                        user_logger.trace(
                            "TRACE: target observation # {} last observed "
                            "{}".format(target["obs_cntr"],
                                        target["last_observed"]))
                        user_logger.trace(
                            "TRACE: observer after track\n {}".format(
                                observer))

                    # loop continuation checks
                    delta_time = time.time() - session.start_time
                    user_logger.trace(
                        "TRACE: time elapsed {} sec".format(delta_time))
                    user_logger.trace(
                        "TRACE: total obs duration {} sec".format(
                            obs_duration))
                    if obs_duration > 0:
                        time_remaining = obs_duration - delta_time
                        user_logger.trace(
                            "TRACE: time remaining {} sec".format(
                                time_remaining))

                        next_target = obs_targets[(tgt_cntr + 1) %
                                                  len(obs_targets)]
                        user_logger.trace("TRACE: next target before cadence "
                                          "check:\n{}".format(next_target))
                        # check if there is a cadence target that must be run
                        # instead of next target
                        for next_cadence_tgt_idx in range(
                                tgt_cntr + 1, len(obs_targets)):
                            next_cadence_target = obs_targets[
                                next_cadence_tgt_idx % len(obs_targets)]
                            if next_cadence_target["cadence"] > 0:
                                user_logger.trace(
                                    "TRACE: time needed for next obs "
                                    "{} sec".format(
                                        next_cadence_target["cadence"]))
                                next_target = obs_targets[next_cadence_tgt_idx
                                                          % len(obs_targets)]
                                continue
                        user_logger.trace("TRACE: next target after cadence "
                                          "check:\n{}".format(next_target))
                        user_logger.trace("TRACE: time needed for next obs "
                                          "{} sec".format(
                                              next_target["duration"]))
                        if (time_remaining < 1.0
                                or time_remaining < next_target["duration"]):
                            user_logger.info(
                                "Scheduled observation time lapsed - ending observation"
                            )
                            done = True
                            break

                # during dry-run when sessions exit time is reset so will be incorrect
                # outside the loop
                observation_timer = time.time()

                if obs_duration < 0:
                    user_logger.info(
                        "Observation list completed - ending observation")
                    done = True

                # for multiple loop, check start lst of next loop
                if next_start_lst is not None:
                    check_local_lst = observer.sidereal_time()
                    if (check_local_lst > next_start_lst) or (not _next_day(
                            next_start_lst, next_end_lst, check_local_lst)):
                        user_logger.info("Moving to next LST loop")
                        done = True

                # End if there is nothing to do
                if not targets_visible:
                    user_logger.warning(
                        "No more targets to observe - stopping script "
                        "instead of hanging around")
                    done = True

    user_logger.trace("TRACE: observer at end\n {}".format(observer))
    # display observation cycle statistics
    # currently only available for single LST range observations
    if nr_obs_loops < 2:
        print
        user_logger.info("Observation loop statistics")
        total_obs_time = observation_timer - session.start_time
        if obs_duration < 0:
            user_logger.info("Single run through observation target list")
        else:
            user_logger.info("Desired observation time {:.2f} sec "
                             "({:.2f} min)".format(obs_duration,
                                                   obs_duration / 60.0))
        user_logger.info("Total observation time {:.2f} sec "
                         "({:.2f} min)".format(total_obs_time,
                                               total_obs_time / 60.0))
        if len(obs_targets) > 0:
            user_logger.info("Targets observed :")
            for unique_target in np.unique(obs_targets["name"]):
                cntrs = obs_targets[obs_targets["name"] ==
                                    unique_target]["obs_cntr"]
                durations = obs_targets[obs_targets["name"] ==
                                        unique_target]["duration"]
                if np.isnan(durations).any():
                    user_logger.info("{} observed {} times".format(
                        unique_target, np.sum(cntrs)))
                else:
                    user_logger.info("{} observed for {} sec".format(
                        unique_target, np.sum(cntrs * durations)))
        print
Example #28
0
        if opts.ap in [ant.name]:
            receptor = ant

    if receptor is None:
        raise RuntimeError("Receptor under test is not in controlled array")

    # Set sensor strategies"
    kat.ants.set_sampling_strategy("lock", "event")
    kat.ants.set_sampling_strategy("ap.indexer-position", "event")

    if not kat.dry_run and receptor.req.mode('STOP'):
        user_logger.info("Setting Antenna Mode to 'STOP', "
                         "Powering on Antenna Drives.")
        time.sleep(2)
    else:
        if not kat.dry_run:
            user_logger.error("Unable to set Antenna mode to 'STOP'.")

    for taz, tel, band in targetlist:
        for i in range(int(opts.num_repeat)):
            target = katpoint.Target('Name, azel, %s, %s' % (taz, tel))
            track(receptor,
                  target,
                  ridx_position=band,
                  duration=opts.dwell_time,
                  dry_run=kat.dry_run)
            user_logger.info("Elevation: '%s' "
                             "Patterns attempted: '%s' "
                             "Contractual cycles: '%s'." % (tel, i + 1, 11 *
                                                            (i + 1)))
Example #29
0
        "Please specify at least one target argument via name ('Cygnus A'), "
        "description ('azel, 20, 30') or catalogue file name ('sources.csv')")

# Check basic command-line options and obtain a kat object connected to the appropriate system
with verify_and_connect(opts) as kat:
    targets = collect_targets(kat, args)

    # Initialise a capturing session (which typically opens an HDF5 file)
    with start_session(kat, **vars(opts)) as session:
        # Use the command-line options to set up the system
        session.standard_setup(**vars(opts))
        if not opts.no_delays and not kat.dry_run:
            if session.dbe.req.auto_delay('on'):
                user_logger.info("Turning on delay tracking.")
            else:
                user_logger.error('Unable to turn on delay tracking.')
        elif opts.no_delays and not kat.dry_run:
            if session.dbe.req.auto_delay('off'):
                user_logger.info("Turning off delay tracking.")
            else:
                user_logger.error('Unable to turn off delay tracking.')
            if session.dbe.req.zero_delay():
                user_logger.info("Zeroed the delay values.")
            else:
                user_logger.error('Unable to zero delay values.')

        all_ants = session.ants
        # Form scanning antenna subarray (or pick the first antenna as the default scanning antenna)
        scan_ants = ant_array(
            kat, opts.scan_ants if opts.scan_ants else session.ants[0],
            'scan_ants')
Example #30
0
def track(ant, target, ridx_position='l', duration=10, dry_run=False):

    # TODO: make the indexer timeout configurable parameter
    indexer_timeout = 120

    ant.req.mode('STOP')
    if not dry_run:
        # Added sleep to wait for AP brakes to engage
        time.sleep(2)
        result = wait_until_sensor_equals(5.0, ant.name + '_mode', 'STOP')
        if result[0] == False:
            user_logger.error("Failed to set AP to 'STOP' mode. "
                              "Indexer commands will not be processed.")
            return

    user_logger.info("Setting initial RI on %s to position : %s " %
                     (ant.name, ridx_position.upper()))

    ant.req.ap_set_indexer_position(ridx_position)
    if not dry_run:
        result = wait_until_sensor_equals(indexer_timeout,
                                          ant.name + '_ap_indexer_position',
                                          ridx_position)
    else:
        result = (True, ridx_position)

    if result[0] == False:
        ridx_position_raw = kat.sensors.get(
            ant.name + '_ap_indexer_position_raw', None).get_value()
        user_logger.error(
            "Timed out while waiting %s seconds for "
            "indexer to reach '%s' position. "
            "Last position reading was %s degrees." %
            (indexer_timeout, ridx_position.upper(), ridx_position_raw))

    # TODO: make this sequence easier to configure
    ridx_sequence = [
        'u', 'l', 'x', 's', 'l', 'u', 's', 'x', 'u', 'l', 's', 'x', 'l', 'u',
        'x', 's', 'u', 'x', 'l', 's', 'l', 's'
    ]

    # Cycling indexer positions
    if not dry_run:
        for pos in ridx_sequence:
            ridx_last_position = kat.sensors.get(
                ant.name + '_ap_indexer_position', None).get_value()
            ridx_movement_start_time = time.time()
            user_logger.info("--- Moving RI to position: '%s' ---" %
                             pos.upper())
            ant.req.ap_set_indexer_position(pos)

            result = wait_until_sensor_equals(
                indexer_timeout, ant.name + '_ap_indexer_position', pos)
            user_logger.debug("Request result: '%s', "
                              "last sensor reading: '%s'" %
                              (result[0], result[1]))

            if result[0] == False:
                ridx_position_raw = kat.sensors.get(
                    ant.name + '_ap_indexer_position_raw', None).get_value()
                ridx_brakes_released = kat.sensors.get(
                    ant.name + '_ap_ridx_brakes_released', None).get_value()

                user_logger.error("Timed out while waiting %s seconds "
                                  "for indexer to reach '%s' position. "
                                  "Last position reading was %s degrees. "
                                  "Brakes released: '%s'. " %
                                  (indexer_timeout, pos.upper(),
                                   ridx_position_raw, ridx_brakes_released))

            ridx_current_position = kat.sensors.get(
                ant.name + '_ap_indexer_position', None).get_value()
            time_to_index = time.time() - ridx_movement_start_time
            if ridx_current_position in ['undefined']:
                user_logger.warning("Movement ended in undefined position")
            else:
                user_logger.info(
                    "RIDX from '%s' to '%s' position "
                    "took '%s' seconds." %
                    (ridx_last_position.upper(), ridx_current_position.upper(),
                     time_to_index))

            # 60 seconds comes from the antenna specification
            if (time_to_index > 60.0):
                user_logger.warning("Indexer took longer than 60 seconds!")

            user_logger.info("Dwell for %s seconds before "
                             "going to next position." % duration)
            time.sleep(duration)

        user_logger.info("Pattern complete. Heading to next sky target.")