def track(ants, target, duration=10, dry_run=False): print "Target :", target # send this target to the antenna. ants.req.target(target.description) print "Target desc. : ", target.description ant_names = ','.join([ant.name for ant in ants]) ants.req.mode("POINT") user_logger.info("Slewing %s to target : %r" % (ant_names, target)) #Wait for antenna to lock onto target locks = 0 if not dry_run: for ant_x in ants: if ant_x.wait('lock', True, timeout=300): locks += 1 print "locks status:", ant_x.name, locks, len(ants) else: locks = len(ants) if len(ants) == locks: user_logger.info( "Target reached : %r wait for %d seconds before slewing to the next target" % (target, duration)) if not dry_run: time.sleep(duration) user_logger.info("Test complete : %r" % (target, )) return True else: user_logger.warning("Unable to track Target : %r Check %s sensors " % (target, ant_names)) return False
def check_digitisers(ant): if ant.sensor.dig_version_list.get_value(): print("version: %s" % ant.sensor.dig_version_list.get_value().split()[2]) if ant.sensor.dig_selected_band.get_value() not in ["u", "l", "s", "x"]: user_logger.warning(" digitiser is in %s band. expected u, l, s or x band" % ant.sensor.dig_selected_band.get_value()) else: print("digitiser is in %s band" % ant.sensor.dig_selected_band.get_value())
def check_receivers(ant): if ant.sensor.rsc_rsc_he_compressor_state.get_value() == 'unavailable': raise RuntimeError("helium compressor is unavailable") if ant.sensor.rsc_rxl_state.get_value() == 'unavailable': raise RuntimeError("receiver state is unavailable") rxl_temp = ant.sensors.rsc_rxl_rfe1_temperature.get_value() if rxl_temp <= 30.0: print("L-band rfe1 temperature is ok :) currently at {:.3f}". format(rxl_temp)) if not ant.sensor.rsc_rxl_lna_h_power_enabled.get_value(): user_logger.warning(" L-band receiver hpol LNA power is not enabled. switch on the hpol LNA power") else: print(":) receiver hpol LNA power is ON") if not ant.sensor.rsc_rxl_lna_v_power_enabled.get_value(): user_logger.warning(" L-band receiver vpol LNA power is not enabled. switch on the vpol LNA power") else: print(":) receiver vpol LNA power is ON") elif rxl_temp > 30.0 and rxl_temp < 100.0: user_logger.warning(" L-band rfe1 temperature is {:.3f}. check if the temp is rising or cooling down". format(rxl_temp)) else: user_logger.warning(" L-band rfe1 temperature is warm. currently at {:.3f}. alert the site technician". format(rxl_temp)) indexer_angle = ant.sensor.ap_indexer_position_raw.get_value() print("receiver indexer value is %d." % indexer_angle) ril=ant.sensor.ap_indexer_position.get_value().upper() if ril not in ["u", "l", "s", "x"]: user_logger.warning(" AP indexer in unknown position") else: print("receiver indexer is at the %s-band position" % ril)
def check_sensors(ped, sensor_list, test_false=False): errors_found=False for atr in sensor_list: if getattr(ped, atr).get_value(): errors_found=True if not test_false: user_logger.warning(" Error detected: %s is %s" % (atr,getattr(ped, atr).get_value())) return errors_found
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!")
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
def scan(ants, target, duration=30.0, start=(-3.0, 0.0), end=(3.0, 0.0), index=-1, dry_run=False,projection = ('ARC', 0., 0.)): # Convert description string to target object, or keep object as is if not isinstance(target, katpoint.Target): target = katpoint.Target(target) scan_name = 'scan' if index < 0 else 'scan %d' % (index,) user_logger.info("Initiating %g-second scan across target '%s'" % (duration, target.name)) # This already sets antennas in motion if in mode POINT set_target(ants, target) user_logger.info('slewing to start of %s', scan_name) # Move each antenna to the start position of the scan ants.req.scan_asym(start[0], start[1], end[0], end[1],duration, projection) ants.req.mode('POINT') # Wait until they are all in position (with 5 minute timeout) locks = 0 if not dry_run : for ant_x in ants: if ant_x.wait('lock', True, timeout=300): locks +=1 print "locks status:", ant_x.name , locks,len(ants) else: locks = len(ants) if len(ants)==locks: user_logger.info('start of %s reached' % (scan_name,)) if not dry_run : #time.sleep(duration) user_logger.info('performing %s' % (scan_name,)) # Start scanning the antennas ants.req.mode('SCAN') # Wait until they are all finished scanning (with 5 minute timeout) scanc = 0 for ant_x in ants: if ant_x.wait('scan_status', 'after', timeout=300): scanc +=1 print "scan status:", ant_x.name , scanc,len(ants) user_logger.info('%s complete' % (scan_name,)) return True else: user_logger.warning("Unable to Scan Target : %r Check %s sensors " % (target,','.join([ant.name for ant in ants]))) return False return True
def track(ants, target, duration=10): # send this target to the antenna. ants.req.target(target) ants.req.mode("POINT") user_logger.info("Slewing to target : %s" % target.name) # wait for antennas to lock onto target locks = 0 for ant_x in ants: if ant_x.wait("lock", True, 300): locks += 1 if len(ants) == locks: user_logger.info("Tracking Target : %s for %s seconds" % (target.name, str(duration))) time.sleep(duration) user_logger.info("Target tracked : %s " % (target.name, )) return True else: user_logger.warning("Unable to track Targe : %s " % (target.name, )) return False
def track(ants, target, index='l', duration=1, dry_run=False): # send this target to the antenna. ants.req.target(target.description) ant_names = ','.join([ant.name for ant in ants]) ants.req.mode("POINT") user_logger.info("Slewing %s to target : %r" % (ant_names, target)) ants.req.ap_set_indexer_position(index) user_logger.info("Changing indexers of %s to position : %r" % (ant_names, index)) #if not dry_run : time.sleep(duration) if ants.wait('lock', True, timeout=300): user_logger.info("Tracking Target : %r for %d seconds" % (target, duration)) time.sleep(duration) user_logger.info("Target tracked : %r" % (target, )) return True else: user_logger.warning("Unable to track Target : %r " % (target, )) return False
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
def track(ants, target, duration=10): # send this target to the antenna. ants.req.target(target.description) ants.req.mode("POINT") user_logger.info("Slewing to target : %s" % target.name) # wait for antennas to lock onto target locks = 0 for ant_x in ants: ant_x.set_sampling_strategy("lock", ("event", )) if ant_x.wait(sensor_name="lock", condition_or_value=True, timeout=300): locks += 1 if len(ants) == locks: user_logger.info("Tracking Target : %s for %s seconds" % (target.name, str(duration))) time.sleep(duration) user_logger.info("Target tracked : %s " % (target.name, )) return True else: user_logger.warning("Unable to track Targe : %s " % (target.name, )) return False
siggen_power_list = np.array([float(siggen_power_str[0])]) if len(siggen_power_str) == 2: siggen_power_list = np.array( [float(siggen_power_str[0]), float(siggen_power_str[1])]) if len(siggen_power_str) == 3: siggen_power_list = np.arange(float(siggen_power_str[0]), float(siggen_power_str[1]), float(siggen_power_str[2])) siggen_power = siggen_power_list[0] # Check options and build KAT configuration, connecting to proxies and devices with verify_and_connect(opts) as kat: observation_sources = collect_targets(kat, args) if opts.force_siggen and kat.dry_run: user_logger.warning( "The signal generator commands are being used during a dry-run") # Quit early if there are no sources to observe if len(observation_sources.filter(el_limit_deg=opts.horizon)) == 0: user_logger.warning( "No targets are currently visible - please re-run the script later" ) 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()
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
parser.add_option('-t', '--track-duration', type='float', default=60.0, help='Length of the drift scan for each source, in seconds (default=%default)') # Set default value for any option (both standard and experiment-specific options) parser.set_defaults(description='Track Test') # Parse the command line opts, args = parser.parse_args() with verify_and_connect(opts) as kat: observation_sources = katpoint.Catalogue(antenna=kat.sources.antenna) args_target_obj = collect_targets(kat,args) observation_sources.add(args_target_obj) # Quit early if there are no sources to observe if len(observation_sources.filter(el_limit_deg=opts.horizon)) == 0: user_logger.warning("No targets are currently visible - please re-run the script later") else: # Start capture session, which creates HDF5 file with start_session(kat, **vars(opts)) as session: session.standard_setup(**vars(opts)) session.capture_start() import ephem observer = ephem.Observer() observer.lon='21:24:38.5' observer.lat='-30:43:17.3' observer.elevation = 1038.0 ## 0) Track moon for number of seconds # Iterate through source list, picking the next one that is up for target in observation_sources.iterfilter(el_limit_deg=opts.horizon): user_logger.info(target)
def _get_scan_area_extents(target_list, antenna_, obs_start_ts, offset_deg=0.1): """Return the elevation, azimuth extents, and time extents of the scan.""" antenna = copy.copy(antenna_) antenna.observer.date = obs_start_ts is_rising_list = [] el_list = [] az_list = [] time_list = [] for target in target_list: _, el = target.azel(timestamp=obs_start_ts) el_list.append(el) if el < 0: user_logger.warning( target.name + "is below the horizon (%s deg at %s)", el, obs_start_ts) user_logger.debug('Min elevation of scan area at start: %s', min(el_list)) user_logger.debug('Max elevation of scan area at start: %s', max(el_list)) el_just_below_lowest = min(el_list) - np.radians(_HORIZON_ANGLE_OFFSET_DEG) antenna.observer.horizon = el_just_below_lowest for target in target_list: next_transit = antenna.observer.next_transit(target.body) next_setting = antenna.observer.next_setting(target.body) next_rising = antenna.observer.next_rising(target.body) is_rising = next_transit < next_setting < next_rising is_rising_list.append(is_rising) user_logger.debug("Is Target rising :%s, %s" % (target.body, is_rising)) if all(is_rising_list): # Rising sources antenna.observer.horizon = max(el_list) + np.radians( offset_deg) # top point user_logger.debug('Highest elevation for rising source: %s', max(el_list)) for target in target_list: antenna.observer.next_rising( target.body) # rise through the scan line az_list.append(target.body.rise_az) time_list.append(target.body.rise_time) else: antenna.observer.horizon = min(el_list) - np.radians( offset_deg) # bottom point user_logger.debug('Lowest elevation for setting source: %s', min(el_list)) for target in target_list: antenna.observer.next_setting( target.body) # Set through the scan line az_list.append(target.body.set_az) time_list.append(target.body.set_time) min_time = katpoint.Timestamp(min(time_list)) max_time = katpoint.Timestamp(max(time_list)) user_logger.debug( "Scan Area Points: el: %s, az: %s %s, time: %s %s", antenna.observer.horizon, min(az_list), max(az_list), min_time, max_time, ) return ( antenna.observer.horizon, min(az_list), max(az_list), min_time, max_time, )
beam.obs_meta['ants'] = [(ant.name + beam.pol) for ant in ants] beam.obs_meta['target'] = target.description if cal_target and len(ants) >= 4: beam.obs_meta['cal_target'] = cal_target.description if len(ants) > 1: user_logger.info('Phasing up beamformer combining %d antennas' % (len(ants),)) # Get the latest gain corrections from system weights, weight_times = get_weights(cbf) if not weights: raise ValueError('No beamformer weights are available') # All inputs in use in beamformer (both pols), for checking weight age inputs = reduce(lambda inp, beam: inp + beam.inputs, beams, []) age = time.time() - min(weight_times[inp] for inp in inputs) if age > 2 * 60 * 60: user_logger.warning('Beamformer weights are %d hours old, using them anyway' % (age / 60 / 60,)) # Phase up beamformer using latest weights for beam in beams: phase_up(cbf, weights, inputs=beam.inputs, bf=beam.name, style=opts.style) time.sleep(1) else: # The single-dish case does not need beamforming user_logger.info('Set beamformer weights to select single dish') for beam in beams: select_ant(cbf, input=beam.inputs[0], bf=beam.name) time.sleep(1) # Start beamformer session with BeamformerSession(cbf, beams) as bf_session: # Get onto beamformer target corr_session.label('track')
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
# # RvR -- temporarily added to allow manual start of metadata # Pick a target, either explicitly or the closest strong one if len(args) > 0: target = collect_targets(kat, [args[0]]).targets[0] else: # Get current position of first antenna in the list (assume the rest are the same or close) if kat.dry_run: current_az, current_el = session._fake_ants[0][2:] else: current_az = session.ants[ 0].sensor.pos_actual_scan_azim.get_value() current_el = session.ants[ 0].sensor.pos_actual_scan_elev.get_value() if current_az is None: user_logger.warning( "Sensor kat.%s.sensor.pos_actual_scan_azim failed - using default azimuth" % (session.ants[0].name)) current_az = 0. if current_el is None: user_logger.warning( "Sensor kat.%s.sensor.pos_actual_scan_elev failed - using default elevation" % (session.ants[0].name)) current_el = 30. current_pos = katpoint.construct_azel_target( katpoint.deg2rad(current_az), katpoint.deg2rad(current_el)) # Get closest strong source that is up strong_sources = kat.sources.filter(el_limit_deg=[20, 75], flux_limit_Jy=100, flux_freq_MHz=opts.centre_freq) if len(strong_sources) == 0: user_logger.warning(
opts, args = parser.parse_args() # Check options and build KAT configuration, connecting to proxies and devices with verify_and_connect(opts) as kat: with start_session(kat, **vars(opts)) as session: session.standard_setup(**vars(opts)) # General: 4 Hz dumps, full speed movement. # Test elevation scan: Az=0, El=15 to 60. Stop at 70 for 10 seconds. El from 70 to 15. continue_test=True if not kat.dry_run: # User position sensors to make sure the system is in a safe place before starting movement current_az = session.ants[0].sensor.pos_actual_scan_azim.get_value() current_el = session.ants[0].sensor.pos_actual_scan_elev.get_value() if current_az is None: user_logger.warning("Sensor kat.%s.sensor.pos_actual_scan_azim failed - using default azimuth" % (session.ants[0].name)) continue_test=False if current_el is None: user_logger.warning("Sensor kat.%s.sensor.pos_actual_scan_elev failed - using default elevation" % (session.ants[0].name)) continue_test=False elif current_el < 20.: continue_test=False if continue_test: #only continue if the antenna is in a safe place to move session.label('0.5 deg/sec') kat.ants.req.mode('STOP') time.sleep(5) kat.ants.req.ap_rate(0.5,0) time.sleep(40)
# Loop over sources in catalogue in sequence for n, source in enumerate(sources): # If it is time for a bandpass calibrator to be visited on an interval basis, do so if opts.bpcal_interval is not None and time.time( ) - time_of_last_bpcal >= opts.bpcal_interval: time_of_last_bpcal = time.time() for bpcal in sources.filter('bpcal'): session.label('track') session.track(bpcal, duration=duration['bpcal']) # Visit source if it is not a bandpass calibrator (or bandpass calibrators are not treated specially) if opts.bpcal_interval is None or 'bpcal' not in source.tags: # Set the default track duration for a target with no recognised tags track_duration = opts.target_duration for tag in source.tags: track_duration = duration.get(tag, track_duration) session.label('track') source_observed[n] = session.track(source, duration=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, )) loop = False break if loop and not any(source_observed): user_logger.warning( 'All imaging targets and gain cals are currently below horizon, stopping script' ) loop = False
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
user_logger.info("This script used values found in katconf/katconfig") user_logger.info( "Reading file katconf:'katconfig/user/attenuation/mkat/dig_attenuation_%s.csv'" % (band)) file_string = katconf.resource_string( 'katconfig/user/attenuation/mkat/dig_attenuation_%s.csv' % (band)) tmp_data = np.loadtxt(StringIO.StringIO(file_string), dtype=np.str, delimiter=',') 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 check_sensors(ant.sensor, azim_limits): any_errors = True else: print(":) AP not in Azimuth Limit") elev_limits=[ "ap_elev_emergency2_limit_down_reached", "ap_elev_emergency2_limit_up_reached", "ap_elev_emergency_limit_down_reached", "ap_elev_emergency_limit_up_reached", "ap_elev_hard_limit_down_reached", "ap_elev_hard_limit_up_reached", "ap_elev_soft_limit_down_reached", "ap_elev_soft_limit_up_reached", "ap_elev_soft_prelimit_down_reached", "ap_elev_soft_prelimit_up_reached" ] if check_sensors(ant.sensor, elev_limits): any_errors = True else: print(":) AP not in Elevation Limit") if any_errors: print('\n') user_logger.warning(" Some errors detected, investigate before accepting %s" % ant.name) else: print("\n{} has passed the handover test".format(opts.ant)) # -fin- print("check_ant_AR1.py: stop\n")
# load file from head node via katconf server (e.g. gps-ops.txt) file_path = 'katexternaldata/catalogues/%s' % (args[0]) user_logger.info('Adding TLE from file: %s', file_path) lines = katconf.resource_string(file_path).split('\n') lines = [line + '\r\n' for line in lines if len(line) > 0] observation_sources.add_tle(lines) except ( IOError, ValueError ): #IOError or ValueError : # If the file failed to load assume it is a target string args_target_obj = collect_targets(kat, args) observation_sources.add(args_target_obj) # Quit early if there are no sources to observe if len(observation_sources.filter(el_limit_deg=opts.horizon)) == 0: user_logger.warning( "No targets are currently visible - please re-run the script later" ) else: # Start capture session, which creates HDF5 file with start_session(kat, **vars(opts)) as session: session.standard_setup(**vars(opts)) session.capture_start() # Get current position of first antenna in the list (assume the rest are the same or close) if kat.dry_run: current_az, current_el = session._fake_ants[0][2:] else: current_az = session.ants[ 0].sensor.pos_actual_scan_azim.get_value() current_el = session.ants[ 0].sensor.pos_actual_scan_elev.get_value() if current_az is None:
for target in observation_sources: session.label('raster') user_logger.info( "Initiating radial scan (%d %g-second scans extending %g degrees) on target '%s'" % (opts.num_scans, opts.scan_duration, opts.scan_extent, target.name)) # Calculate average time that noise diode is operated per scan, to add to scan duration in check below nd_time = session.nd_params['on'] + session.nd_params['off'] nd_time *= opts.scan_duration / max(session.nd_params['period'], opts.scan_duration) nd_time = nd_time if session.nd_params['period'] >= 0 else 0. # Check whether the target will be visible for entire duration of radial scan if not session.target_visible( target, (opts.scan_duration + nd_time) * opts.num_scans): user_logger.warning( "Skipping radial scan, as target '%s' will be below horizon" % (target.name, )) continue # Iterate through angles and scan across target for ind, angle in enumerate( np.arange(0., np.pi, np.pi / opts.num_scans)): offset = np.array( (np.cos(angle), -np.sin(angle))) * opts.scan_extent / 2. * (-1)**ind session.scan(target, duration=opts.scan_duration, start=-offset, end=offset, index=ind, projection=opts.projection, announce=False)
parser.add_option( '--search-fine', action="store_true", default=False, help= 'Do a fine grained pointscan with an extent of 2 degree and a duration of 60 seconds.' 'The intention of this is for use in Ku-band obsevations where the beam is 8 arc-min .*DEPRECATED*' ) parser.set_defaults(description='Point source scan', dump_rate=None) # Parse the command line opts, args = parser.parse_args() # Handle deprecated options if opts.quick: user_logger.warning( "The --quick option is deprecated, use --style=quick instead") opts.style == 'quick' elif opts.fine: user_logger.warning( "The --fine option is deprecated, use --style=fine instead") opts.style == 'fine' elif opts.search_fine: user_logger.warning( "The --search-fine option is deprecated, use --style=search-fine instead" ) opts.style == 'search-fine' elif opts.source_strength != 'none': user_logger.warning( "The --source-strength=blah option is deprecated, use --style=blah instead" ) opts.style = opts.source_strength
pointing_sources = kat.sources.filter(tags='radec') user_logger.info( "No valid targets specified, loaded default catalogue with %d targets" % (len(pointing_sources), )) # Remove sources in skip catalogue file, if provided if opts.skip_catalogue is not None and os.path.exists(opts.skip_catalogue): skip_sources = katpoint.Catalogue(file(opts.skip_catalogue)) for target in skip_sources: pointing_sources.remove(target.name) user_logger.info("After skipping, %d targets are left" % (len(pointing_sources), )) # Quit early if there are no sources to observe if len(pointing_sources) == 0: user_logger.warning( "Empty point source catalogue or all targets are skipped") elif len(pointing_sources.filter(el_limit_deg=opts.horizon)) == 0: user_logger.warning( "No targets are currently visible - please re-run the script later" ) else: # Observed targets will be written back to catalogue file, or into the void skip_file = file(opts.skip_catalogue, "a") \ if opts.skip_catalogue is not None and not kat.dry_run else StringIO() with start_session(kat, **vars(opts)) as session: session.standard_setup(**vars(opts)) session.capture_start() start_time = time.time() targets_observed = [] # Keep going until the time is up
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.")
np.degrees(target.astrometric_radec()) + offset / (np.cos(target.astrometric_radec()[1]), 1.0)) offsettarget = katpoint.Target( 'offset,radec, %s , %s' % (offset_targetval[0] / 15., offset_targetval[1]) ) # the ra is in decimal hours for some reason user_logger.info( "Target & offset seperation = %s " % (np.degrees(target.separation(offsettarget)))) session.track(target, duration=0, announce=False) else: offsetloop = False if not opts.max_duration < 0 and (time.time() - start_time >= opts.max_duration): user_logger.warning( "Maximum duration of %g seconds has elapsed - stopping script" % (opts.max_duration, )) keep_going = False break targets_observed.append(target.name) if len(targets_observed) > opts.number_sources - 1: keep_going = False break # The default is to do only one iteration through source list if opts.max_duration <= 0.0: keep_going = False if keep_going and len(targets_observed) == targets_before_loop: user_logger.warning( "No targets are currently visible - stopping script instead of hanging around"
atten_sensor = {} for ant in kat.ants: for pol in 'hv': input_name = ant.name + pol atten_name = "dig_{}_band_rfcu_{}pol_attenuation".format(band, pol) atten_sensor[input_name] = ant.sensor[ atten_name] # Deal with KeyError if no such sensor attenuation_old[input_name] = atten_sensor[input_name].get_value() user_logger.info("%s %s pol band %r has attenuation = %f", ant.name, pol, band, attenuation_old[input_name]) # Quit early if there are no sources to observe valid_targets = True if not strong_sources.filter(el_limit_deg=opts.horizon): user_logger.warning( "No strong source targets are currently visible - please re-run the script later" ) valid_targets = False if not cold_sources.filter(el_limit_deg=opts.horizon): user_logger.warning( "No cold source targets are currently visible - please re-run the script later" ) valid_targets = False if valid_targets: # Start capture session, which creates HDF5 file with start_session(kat, **vars(opts)) as session: session.standard_setup(**vars(opts)) session.capture_start() target_list = [] target_list.append( (cold_sources, opts.cold_duration, "track_before",