Antenna Classification Daily Summary¶

by Josh Dillon last updated June 19, 2023

This notebook parses and summarizes the output of the file_calibration notebook to produce a report on per-antenna malfunctions on a daily basis.

Quick links:

• Summary of Per Antenna Issues¶

• Figure 1: Per File Overall Antenna Classification Summary¶

• Figure 2: Per Classifier Antenna Flagging Summary¶

• Figure 3: Array Visualization of Overall Daily Classification¶

In [1]:
import os
os.environ['HDF5_USE_FILE_LOCKING'] = 'FALSE'
import h5py
import hdf5plugin  # REQUIRED to have the compression plugins available
import numpy as np
import pandas as pd
import glob
import os
import matplotlib.pyplot as plt
from hera_cal import io, utils
from hera_qm import ant_class
from uvtools.plot import plot_antpos, plot_antclass
%matplotlib inline
from IPython.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))
_ = np.seterr(all='ignore')  # get rid of red warnings
%config InlineBackend.figure_format = 'retina'

Settings¶

In [2]:
# Parse settings from environment
ANT_CLASS_FOLDER = os.environ.get("ANT_CLASS_FOLDER", "./")
SUM_FILE = os.environ.get("SUM_FILE", None)
# ANT_CLASS_FOLDER = "/mnt/sn1/2460330"
# SUM_FILE = "/mnt/sn1/2460330/zen.2460330.25463.sum.uvh5"
OC_SKIP_OUTRIGGERS = os.environ.get("OC_SKIP_OUTRIGGERS", "TRUE").upper() == "TRUE"

for param in ['ANT_CLASS_FOLDER', 'SUM_FILE', 'OC_SKIP_OUTRIGGERS']:
    print(f"{param} = '{eval(param)}'")
ANT_CLASS_FOLDER = '/mnt/sn1/data2/2460428'
SUM_FILE = '/mnt/sn1/data2/2460428/zen.2460428.37690.sum.uvh5'
OC_SKIP_OUTRIGGERS = 'True'
In [3]:
if SUM_FILE is not None:
    from astropy.time import Time, TimeDelta
    utc = Time(float(SUM_FILE.split('zen.')[-1].split('.sum.uvh5')[0]), format='jd').datetime
    print(f'Date: {utc.month}-{utc.day}-{utc.year}')
Date: 4-27-2024
In [4]:
# set thresholds for fraction of the day
overall_thresh = .1
all_zero_thresh = .1
eo_zeros_thresh = .1
xengine_diff_thresh = .1
cross_pol_thresh = .5
bad_fem_thresh = .1
high_power_thresh = .1
low_power_thresh = .1
low_corr_thresh = .1
bad_shape_thresh = .5
excess_rfi_thresh = .1
chisq_thresh = .25

Load classifications and other metadata¶

In [5]:
# Load csvs
csv_files = sorted(glob.glob(os.path.join(ANT_CLASS_FOLDER, '*.ant_class.csv')))
jds = [float(f.split('/')[-1].split('zen.')[-1].split('.sum')[0]) for f in csv_files]
tables = [pd.read_csv(f).dropna(axis=0, how='all') for f in csv_files]
table_cols = tables[0].columns[1::2]
class_cols = tables[0].columns[2::2]
print(f'Found {len(csv_files)} csv files starting with {csv_files[0]}')
Found 1851 csv files starting with /mnt/sn1/data2/2460428/zen.2460428.16886.sum.ant_class.csv
In [6]:
# parse ant_strings
ap_strs = np.array(tables[0]['Antenna'])
ants = sorted(set(int(a[:-1]) for a in ap_strs))
translator = ''.maketrans('e', 'n') | ''.maketrans('n', 'e')
In [7]:
# get node numbers
node_dict = {ant: 'Unknown' for ant in ants}
try:
    from hera_mc import cm_hookup
    hookup = cm_hookup.get_hookup('default')
    for ant_name in hookup:
        ant = int("".join(filter(str.isdigit, ant_name)))
        if ant in node_dict:
            if hookup[ant_name].get_part_from_type('node')['E<ground'] is not None:
                node_dict[ant] = int(hookup[ant_name].get_part_from_type('node')['E<ground'][1:])
except:
    pass
nodes = sorted(set(node_dict.values()))
In [8]:
def classification_array(col):
    class_array = np.vstack([t[col] for t in tables])
    class_array[class_array == 'good'] = 1.7
    class_array[class_array == 'suspect'] = 1
    class_array[class_array == 'bad'] = 0
    return class_array.astype(float)
In [9]:
if SUM_FILE is not None:
    hd = io.HERADataFastReader(SUM_FILE)
    ap_tuples = [(int(ap[:-1]), {'e': 'Jee', 'n': 'Jnn'}[ap[-1]]) for ap in ap_strs]
    bad_bools = np.mean(classification_array('Antenna Class') == 0, axis=0) > overall_thresh
    bad_aps = [ap_tuples[i] for i in np.arange(len(ap_tuples))[bad_bools]]
    suspect_bools = np.mean(classification_array('Antenna Class') == 1, axis=0) > overall_thresh
    suspect_aps = [ap_tuples[i] for i in np.arange(len(ap_tuples))[suspect_bools] if ap_tuples[i] not in bad_aps]
    good_aps = [ap for ap in ap_tuples if ap not in bad_aps and ap not in suspect_aps]
    overall_class = ant_class.AntennaClassification(bad=bad_aps, suspect=suspect_aps, good=good_aps)
    autos, _, _ = hd.read(bls=[bl for bl in hd.bls if utils.split_bl(bl)[0] == utils.split_bl(bl)[1]], read_flags=False, read_nsamples=False)
    avg_unflagged_auto = {}
    for pol in ['ee', 'nn']:
        unflagged_autos = [autos[bl] for bl in autos if bl[2] == pol and overall_class[utils.split_bl(bl)[0]] != 'bad']
        if len(unflagged_autos) > 0:
            avg_unflagged_auto[pol] = np.mean(unflagged_autos, axis=(0, 1))
        else:
            avg_unflagged_auto[pol] = np.zeros(len(hd.freqs), dtype=complex)

Figure out and summarize per-antenna issues¶

In [10]:
def print_issue_summary(bad_ant_strs, title, notes='', plot=False):
    '''Print report for list of bad antenna polarizations strings'''
    unique_bad_antnums = [int(ap[:-1]) for ap in bad_ant_strs]
    display(HTML(f'<h2>{title}: ({len(bad_ant_strs)} antpols across {len(set([ba[:-1] for ba in bad_ant_strs]))} antennas)</h2>'))
    if len(notes) > 0:
        display(HTML(f'<h4>{notes}</h4>'))
    if len(bad_ant_strs) > 0:
        print(f'All Bad Antpols: {", ".join(bad_ant_strs)}\n')
    for node in nodes:
        if np.any([node == node_dict[a] for a in unique_bad_antnums]):
            aps = [ap for ap in bad_ant_strs if node_dict[int(ap[:-1])] == node]
            whole_ants = [str(wa) for wa in set([int(ap[:-1]) for ap in aps if ap.translate(translator) in bad_ant_strs])]
            single_pols =  [ap for ap in aps if ap.translate(translator) not in bad_ant_strs]
            print(f'Node {node}:')
            print(f'\tAntpols ({len(aps)} total): {", ".join(aps)}')
            print(f'\tWhole Ants ({len(whole_ants)} total): {", ".join(whole_ants)}')
            print(f'\tSingle Pols ({len(single_pols)} total): {", ".join(single_pols)}')
            if plot and SUM_FILE is not None:
                fig, axes = plt.subplots(1, 2, figsize=(12,4), dpi=70, sharey=True, gridspec_kw={'wspace': 0})
                for ax, pol in zip(axes, ['ee', 'nn']):                    
                    ax.semilogy(autos.freqs / 1e6, avg_unflagged_auto[pol], 'k--', label='Average\nUnflagged\nAuto')
                    for ap in aps:
                        ant = int(ap[:-1]), utils.comply_pol(ap[-1])
                        auto_bl = utils.join_bl(ant, ant)
                        if auto_bl[2] == pol:
                            ax.semilogy(autos.freqs / 1e6, np.mean(autos[auto_bl], axis=0), label=ap)
                    ax.legend()
                    ax.set_xlim([40, 299])
                    ax.set_title(f'{title} on Node {node} ({pol}-antennas)')
                    ax.set_xlabel('Frequency (MHz)')
                axes[0].set_ylabel('Single File Raw Autocorrelation')
                plt.tight_layout()
                plt.show() 
In [11]:
# precompute various helpful quantities
all_slopes = np.vstack([t['Autocorr Slope'] for t in tables])
median_slope = np.median(all_slopes)
bad_slopes = np.vstack([t['Autocorr Slope Class'] for t in tables]) == 'bad'
suspect_slopes = np.vstack([t['Autocorr Slope Class'] for t in tables]) == 'suspect'
bad_shapes = np.vstack([t['Autocorr Shape Class'] for t in tables]) == 'bad'
suspect_shapes = np.vstack([t['Autocorr Shape Class'] for t in tables]) == 'suspect'
all_powers = np.vstack([t['Autocorr Power'] for t in tables])
median_power = np.median(all_powers)
bad_powers = np.vstack([t['Autocorr Power Class'] for t in tables]) == 'bad'
suspect_powers = np.vstack([t['Autocorr Power Class'] for t in tables]) == 'suspect'
bad_rfi = np.vstack([t['RFI in Autos Class'] for t in tables]) == 'bad'
suspect_rfi = np.vstack([t['RFI in Autos Class'] for t in tables]) == 'suspect'
In [12]:
# find all zeros
all_zeros_strs = ap_strs[np.mean(np.vstack([t['Dead? Class'] for t in tables]) == 'bad', axis=0) > all_zero_thresh]
In [13]:
# find even/odd zeros
eo_zeros_strs = ap_strs[np.mean(np.vstack([t['Even/Odd Zeros Class'] for t in tables]) == 'bad', axis=0) > eo_zeros_thresh]
eo_zeros_strs = [ap for ap in eo_zeros_strs if ap not in all_zeros_strs] 
In [14]:
# find cross-polarized antennas
cross_pol_strs = ap_strs[np.mean(np.vstack([t['Cross-Polarized Class'] for t in tables]) == 'bad', axis=0) > cross_pol_thresh]
cross_pol_strs = [ap for ap in cross_pol_strs if ap not in all_zeros_strs] 
In [15]:
# find FEM power issues: must be low power, high slope, and bad or suspect in power, slope, rfi, and shape
fem_off_prod = (bad_powers + .5 * suspect_powers) * (bad_slopes + .5 * suspect_slopes)
fem_off_prod *= (bad_rfi + .5 * suspect_rfi) * (bad_shapes + .5 * suspect_shapes)
fem_off_strs = ap_strs[np.mean(fem_off_prod * (all_powers < median_power) * (all_slopes > median_slope), axis=0) > .1]
In [16]:
# find high power issues
high_power_strs = ap_strs[np.mean(bad_powers & (all_powers > median_power), axis=0) > high_power_thresh]
In [17]:
# find other low power issues
low_power_strs = ap_strs[np.mean(bad_powers & (all_powers < median_power), axis=0) > low_power_thresh]
low_power_strs = [ap for ap in low_power_strs if ap not in all_zeros_strs and ap not in fem_off_strs] 
In [18]:
# find low correlation (but not low power)
low_corr_strs = ap_strs[np.mean(np.vstack([t['Low Correlation Class'] for t in tables]) == 'bad', axis=0) > low_corr_thresh]
low_corr_strs = [ap for ap in low_corr_strs if ap not in (set(low_power_strs) | set(all_zeros_strs) | set(fem_off_strs))] 
In [19]:
# find bad bandpasses
bad_bandpass_strs = ap_strs[np.mean(bad_shapes, axis=0) > bad_shape_thresh]
bad_bandpass_strs = [ap for ap in bad_bandpass_strs if ap not in (set(low_power_strs) | set(all_zeros_strs) | set(high_power_strs) | set(fem_off_strs))]
In [20]:
# find antennas with excess RFI
excess_rfi_strs = ap_strs[np.mean(np.vstack([t['RFI in Autos Class'] for t in tables]) == 'bad', axis=0) > excess_rfi_thresh]
excess_rfi_strs = [ap for ap in excess_rfi_strs if ap not in (set(low_power_strs) | set(all_zeros_strs) |  set(fem_off_strs) |
                                                              set(bad_bandpass_strs) | set(high_power_strs))] 
In [21]:
# find bad x-engine diffs
xengine_diff_strs = ap_strs[np.mean(np.vstack([t['Bad Diff X-Engines Class'] for t in tables]) == 'bad', axis=0) > xengine_diff_thresh]
xengine_diff_strs = [ap for ap in xengine_diff_strs if ap not in (set(bad_bandpass_strs) | set(low_power_strs) | set(excess_rfi_strs) | set(low_corr_strs) |
                                                                  set(all_zeros_strs) | set(high_power_strs) | set(fem_off_strs) | set(eo_zeros_strs))]
In [22]:
# find antennas with high redcal chi^2
chisq_strs = ap_strs[np.mean(np.vstack([t['Redcal chi^2 Class'] for t in tables]) == 'bad', axis=0) > chisq_thresh]
chisq_strs = [ap for ap in chisq_strs if ap not in (set(bad_bandpass_strs) | set(low_power_strs) | set(excess_rfi_strs) | set(low_corr_strs) |
                                                    set(all_zeros_strs) | set(high_power_strs) | set(fem_off_strs) | set(eo_zeros_strs) | set(xengine_diff_strs))]
if OC_SKIP_OUTRIGGERS:
    chisq_strs = [ap for ap in chisq_strs if int(ap[:-1]) < 320]
In [23]:
# collect all results
to_print = [(all_zeros_strs, 'All-Zeros', 'These antennas have visibilities that are more than half zeros.'),
            (eo_zeros_strs, 'Excess Zeros in Either Even or Odd Spectra', 
             'These antennas are showing evidence of packet loss or X-engine failure.', True),
            (xengine_diff_strs, 'Excess Power in X-Engine Diffs', 
             'These antennas are showing evidence of mis-written packets in either the evens or the odds.', True),            
            (cross_pol_strs, 'Cross-Polarized', 'These antennas have their east and north cables swapped.'),
            (fem_off_strs, 'Likely FEM Power Issue', 'These antennas have low power, anomolously high slopes, and extra channels identified as RFI.', True),
            (high_power_strs, 'High Power', 'These antennas have high median power.', True),
            (low_power_strs, 'Other Low Power Issues', 'These antennas have low power, but are not all-zeros and not FEM off.', True),
            (low_corr_strs, 'Low Correlation, But Not Low Power', 'These antennas are low correlation, but their autocorrelation power levels look OK.'),
            (bad_bandpass_strs, 'Bad Bandpass Shapes, But Not Bad Power', 
             'These antennas have unusual bandpass shapes, but are not all-zeros, high power, low power, or FEM off.', True),
            (excess_rfi_strs, 'Excess RFI', 'These antennas have excess strucutre (identified as possible RFI) in their bandpassed relative to the ' + \
             'median antenna, but not low or high power or a bad bandpass.', True),
            (chisq_strs, 'Redcal chi^2', 'These antennas have been idenfied as not redundantly calibrating well, even after passing the above checks.')]
In [24]:
def print_high_level_summary():
    for tp in sorted(to_print, key=lambda x: len(x[0]), reverse=True):
        print(f'{len(tp[0])} antpols (on {len(set([ap[:-1] for ap in tp[0]]))} antennas) frequently flagged for {tp[1]}.')
        
def print_all_issue_summaries():
    for tp in to_print:
        print_issue_summary(*tp)

Summary of Per-Antenna Issues¶

In [25]:
print_high_level_summary()
115 antpols (on 93 antennas) frequently flagged for Redcal chi^2.
55 antpols (on 45 antennas) frequently flagged for Excess Power in X-Engine Diffs.
44 antpols (on 22 antennas) frequently flagged for All-Zeros.
25 antpols (on 22 antennas) frequently flagged for Likely FEM Power Issue.
14 antpols (on 12 antennas) frequently flagged for Low Correlation, But Not Low Power.
9 antpols (on 8 antennas) frequently flagged for Excess RFI.
8 antpols (on 6 antennas) frequently flagged for High Power.
7 antpols (on 7 antennas) frequently flagged for Bad Bandpass Shapes, But Not Bad Power.
6 antpols (on 6 antennas) frequently flagged for Other Low Power Issues.
4 antpols (on 2 antennas) frequently flagged for Cross-Polarized.
0 antpols (on 0 antennas) frequently flagged for Excess Zeros in Either Even or Odd Spectra.
In [26]:
print_all_issue_summaries()

All-Zeros: (44 antpols across 22 antennas)

These antennas have visibilities that are more than half zeros.

All Bad Antpols: 47e, 47n, 61e, 61n, 63e, 63n, 64e, 64n, 77e, 77n, 78e, 78n, 88e, 88n, 90e, 90n, 91e, 91n, 105e, 105n, 107e, 107n, 108e, 108n, 176e, 176n, 177e, 177n, 178e, 178n, 241e, 241n, 242e, 242n, 243e, 243n, 246e, 246n, 261e, 261n, 262e, 262n, 272e, 272n

Node 6:
	Antpols (12 total): 47e, 47n, 61e, 61n, 63e, 63n, 64e, 64n, 77e, 77n, 78e, 78n
	Whole Ants (6 total): 64, 77, 78, 47, 61, 63
	Single Pols (0 total): 
Node 9:
	Antpols (12 total): 88e, 88n, 90e, 90n, 91e, 91n, 105e, 105n, 107e, 107n, 108e, 108n
	Whole Ants (6 total): 105, 107, 108, 88, 90, 91
	Single Pols (0 total): 
Node 12:
	Antpols (6 total): 176e, 176n, 177e, 177n, 178e, 178n
	Whole Ants (3 total): 176, 177, 178
	Single Pols (0 total): 
Node 19:
	Antpols (6 total): 241e, 241n, 242e, 242n, 243e, 243n
	Whole Ants (3 total): 241, 242, 243
	Single Pols (0 total): 
Node 20:
	Antpols (6 total): 246e, 246n, 261e, 261n, 262e, 262n
	Whole Ants (3 total): 261, 246, 262
	Single Pols (0 total): 
Node 23:
	Antpols (2 total): 272e, 272n
	Whole Ants (1 total): 272
	Single Pols (0 total): 

Excess Zeros in Either Even or Odd Spectra: (0 antpols across 0 antennas)

These antennas are showing evidence of packet loss or X-engine failure.

Excess Power in X-Engine Diffs: (55 antpols across 45 antennas)

These antennas are showing evidence of mis-written packets in either the evens or the odds.

All Bad Antpols: 9e, 20e, 21e, 28n, 29n, 37e, 37n, 41n, 42n, 51n, 67n, 68e, 81e, 81n, 82e, 82n, 83e, 83n, 93e, 96n, 98e, 98n, 99n, 100e, 100n, 111e, 116e, 116n, 119e, 130e, 131n, 137n, 142n, 145n, 153n, 175n, 181n, 182e, 183n, 188n, 195n, 208e, 208n, 209e, 209n, 212n, 244n, 245n, 251n, 253n, 256n, 268n, 295e, 295n, 320n

Node 1:
	Antpols (2 total): 28n, 29n
	Whole Ants (0 total): 
	Single Pols (2 total): 28n, 29n
Casting complex values to real discards the imaginary part
Casting complex values to real discards the imaginary part
Data has no positive values, and therefore cannot be log-scaled.
No description has been provided for this image
Node 2:
	Antpols (3 total): 9e, 20e, 21e
	Whole Ants (0 total): 
	Single Pols (3 total): 9e, 20e, 21e
No description has been provided for this image
Node 3:
	Antpols (6 total): 37e, 37n, 51n, 67n, 68e, 320n
	Whole Ants (1 total): 37
	Single Pols (4 total): 51n, 67n, 68e, 320n
No description has been provided for this image
Node 4:
	Antpols (2 total): 41n, 42n
	Whole Ants (0 total): 
	Single Pols (2 total): 41n, 42n
No description has been provided for this image
Node 7:
	Antpols (15 total): 81e, 81n, 82e, 82n, 83e, 83n, 98e, 98n, 99n, 100e, 100n, 116e, 116n, 119e, 137n
	Whole Ants (6 total): 98, 100, 81, 82, 83, 116
	Single Pols (3 total): 99n, 119e, 137n
No description has been provided for this image
Node 10:
	Antpols (3 total): 93e, 111e, 130e
	Whole Ants (0 total): 
	Single Pols (3 total): 93e, 111e, 130e
No description has been provided for this image
Node 11:
	Antpols (2 total): 96n, 131n
	Whole Ants (0 total): 
	Single Pols (2 total): 96n, 131n
No description has been provided for this image
Node 13:
	Antpols (4 total): 142n, 181n, 182e, 183n
	Whole Ants (0 total): 
	Single Pols (4 total): 142n, 181n, 182e, 183n
No description has been provided for this image
Node 14:
	Antpols (1 total): 145n
	Whole Ants (0 total): 
	Single Pols (1 total): 145n
No description has been provided for this image
Node 15:
	Antpols (1 total): 188n
	Whole Ants (0 total): 
	Single Pols (1 total): 188n
No description has been provided for this image
Node 16:
	Antpols (1 total): 153n
	Whole Ants (0 total): 
	Single Pols (1 total): 153n
No description has been provided for this image
Node 20:
	Antpols (6 total): 208e, 208n, 209e, 209n, 244n, 245n
	Whole Ants (2 total): 208, 209
	Single Pols (2 total): 244n, 245n
No description has been provided for this image
Node 21:
	Antpols (3 total): 175n, 195n, 212n
	Whole Ants (0 total): 
	Single Pols (3 total): 175n, 195n, 212n
No description has been provided for this image
Node 22:
	Antpols (5 total): 251n, 253n, 268n, 295e, 295n
	Whole Ants (1 total): 295
	Single Pols (3 total): 251n, 253n, 268n
No description has been provided for this image
Node 23:
	Antpols (1 total): 256n
	Whole Ants (0 total): 
	Single Pols (1 total): 256n
No description has been provided for this image

Cross-Polarized: (4 antpols across 2 antennas)

These antennas have their east and north cables swapped.

All Bad Antpols: 93e, 93n, 196e, 196n

Node 10:
	Antpols (2 total): 93e, 93n
	Whole Ants (1 total): 93
	Single Pols (0 total): 
Node 17:
	Antpols (2 total): 196e, 196n
	Whole Ants (1 total): 196
	Single Pols (0 total): 

Likely FEM Power Issue: (25 antpols across 22 antennas)

These antennas have low power, anomolously high slopes, and extra channels identified as RFI.

All Bad Antpols: 3n, 34e, 53n, 54e, 54n, 57e, 66n, 68n, 86n, 93n, 104n, 109n, 112e, 115e, 130n, 170e, 194e, 194n, 199n, 200e, 217e, 255e, 269n, 332e, 332n

Node 1:
	Antpols (1 total): 3n
	Whole Ants (0 total): 
	Single Pols (1 total): 3n
No description has been provided for this image
Node 3:
	Antpols (3 total): 53n, 66n, 68n
	Whole Ants (0 total): 
	Single Pols (3 total): 53n, 66n, 68n
No description has been provided for this image
Node 4:
	Antpols (3 total): 54e, 54n, 57e
	Whole Ants (1 total): 54
	Single Pols (1 total): 57e
No description has been provided for this image
Node 6:
	Antpols (1 total): 34e
	Whole Ants (0 total): 
	Single Pols (1 total): 34e
No description has been provided for this image
Node 8:
	Antpols (2 total): 86n, 104n
	Whole Ants (0 total): 
	Single Pols (2 total): 86n, 104n
No description has been provided for this image
Node 10:
	Antpols (4 total): 93n, 109n, 112e, 130n
	Whole Ants (0 total): 
	Single Pols (4 total): 93n, 109n, 112e, 130n
No description has been provided for this image
Node 11:
	Antpols (1 total): 115e
	Whole Ants (0 total): 
	Single Pols (1 total): 115e
No description has been provided for this image
Node 15:
	Antpols (1 total): 170e
	Whole Ants (0 total): 
	Single Pols (1 total): 170e
No description has been provided for this image
Node 16:
	Antpols (2 total): 194e, 194n
	Whole Ants (1 total): 194
	Single Pols (0 total): 
No description has been provided for this image
Node 17:
	Antpols (2 total): 199n, 217e
	Whole Ants (0 total): 
	Single Pols (2 total): 199n, 217e
No description has been provided for this image
Node 18:
	Antpols (1 total): 200e
	Whole Ants (0 total): 
	Single Pols (1 total): 200e
No description has been provided for this image
Node 21:
	Antpols (2 total): 332e, 332n
	Whole Ants (1 total): 332
	Single Pols (0 total): 
No description has been provided for this image
Node 22:
	Antpols (1 total): 269n
	Whole Ants (0 total): 
	Single Pols (1 total): 269n
No description has been provided for this image
Node 23:
	Antpols (1 total): 255e
	Whole Ants (0 total): 
	Single Pols (1 total): 255e
No description has been provided for this image

High Power: (8 antpols across 6 antennas)

These antennas have high median power.

All Bad Antpols: 45e, 46e, 73e, 73n, 196e, 196n, 232e, 255n

Node 5:
	Antpols (4 total): 45e, 46e, 73e, 73n
	Whole Ants (1 total): 73
	Single Pols (2 total): 45e, 46e
No description has been provided for this image
Node 17:
	Antpols (2 total): 196e, 196n
	Whole Ants (1 total): 196
	Single Pols (0 total): 
No description has been provided for this image
Node 21:
	Antpols (1 total): 232e
	Whole Ants (0 total): 
	Single Pols (1 total): 232e
No description has been provided for this image
Node 23:
	Antpols (1 total): 255n
	Whole Ants (0 total): 
	Single Pols (1 total): 255n
No description has been provided for this image

Other Low Power Issues: (6 antpols across 6 antennas)

These antennas have low power, but are not all-zeros and not FEM off.

All Bad Antpols: 57n, 99e, 119n, 137e, 218n, 251e

Node 4:
	Antpols (1 total): 57n
	Whole Ants (0 total): 
	Single Pols (1 total): 57n
No description has been provided for this image
Node 7:
	Antpols (3 total): 99e, 119n, 137e
	Whole Ants (0 total): 
	Single Pols (3 total): 99e, 119n, 137e
No description has been provided for this image
Node 17:
	Antpols (1 total): 218n
	Whole Ants (0 total): 
	Single Pols (1 total): 218n
No description has been provided for this image
Node 22:
	Antpols (1 total): 251e
	Whole Ants (0 total): 
	Single Pols (1 total): 251e
No description has been provided for this image

Low Correlation, But Not Low Power: (14 antpols across 12 antennas)

These antennas are low correlation, but their autocorrelation power levels look OK.

All Bad Antpols: 27e, 28e, 35n, 86e, 115n, 171n, 196e, 229e, 270e, 270n, 281e, 328e, 328n, 331e

Node 1:
	Antpols (2 total): 27e, 28e
	Whole Ants (0 total): 
	Single Pols (2 total): 27e, 28e
Node 6:
	Antpols (1 total): 35n
	Whole Ants (0 total): 
	Single Pols (1 total): 35n
Node 8:
	Antpols (1 total): 86e
	Whole Ants (0 total): 
	Single Pols (1 total): 86e
Node 10:
	Antpols (2 total): 328e, 328n
	Whole Ants (1 total): 328
	Single Pols (0 total): 
Node 11:
	Antpols (1 total): 115n
	Whole Ants (0 total): 
	Single Pols (1 total): 115n
Node 16:
	Antpols (1 total): 171n
	Whole Ants (0 total): 
	Single Pols (1 total): 171n
Node 17:
	Antpols (1 total): 196e
	Whole Ants (0 total): 
	Single Pols (1 total): 196e
Node 20:
	Antpols (1 total): 229e
	Whole Ants (0 total): 
	Single Pols (1 total): 229e
Node 21:
	Antpols (1 total): 331e
	Whole Ants (0 total): 
	Single Pols (1 total): 331e
Node 22:
	Antpols (1 total): 281e
	Whole Ants (0 total): 
	Single Pols (1 total): 281e
Node 23:
	Antpols (2 total): 270e, 270n
	Whole Ants (1 total): 270
	Single Pols (0 total): 

Bad Bandpass Shapes, But Not Bad Power: (7 antpols across 7 antennas)

These antennas have unusual bandpass shapes, but are not all-zeros, high power, low power, or FEM off.

All Bad Antpols: 27e, 28e, 32n, 87e, 161n, 180n, 266e

Node 1:
	Antpols (2 total): 27e, 28e
	Whole Ants (0 total): 
	Single Pols (2 total): 27e, 28e
No description has been provided for this image
Node 2:
	Antpols (1 total): 32n
	Whole Ants (0 total): 
	Single Pols (1 total): 32n
No description has been provided for this image
Node 8:
	Antpols (1 total): 87e
	Whole Ants (0 total): 
	Single Pols (1 total): 87e
No description has been provided for this image
Node 13:
	Antpols (2 total): 161n, 180n
	Whole Ants (0 total): 
	Single Pols (2 total): 161n, 180n
No description has been provided for this image
Node 22:
	Antpols (1 total): 266e
	Whole Ants (0 total): 
	Single Pols (1 total): 266e
No description has been provided for this image

Excess RFI: (9 antpols across 8 antennas)

These antennas have excess strucutre (identified as possible RFI) in their bandpassed relative to the median antenna, but not low or high power or a bad bandpass.

All Bad Antpols: 18e, 18n, 27n, 31n, 40n, 51e, 92e, 121e, 202n

Node 1:
	Antpols (3 total): 18e, 18n, 27n
	Whole Ants (1 total): 18
	Single Pols (1 total): 27n
No description has been provided for this image
Node 2:
	Antpols (1 total): 31n
	Whole Ants (0 total): 
	Single Pols (1 total): 31n
No description has been provided for this image
Node 3:
	Antpols (1 total): 51e
	Whole Ants (0 total): 
	Single Pols (1 total): 51e
No description has been provided for this image
Node 4:
	Antpols (1 total): 40n
	Whole Ants (0 total): 
	Single Pols (1 total): 40n
No description has been provided for this image
Node 8:
	Antpols (1 total): 121e
	Whole Ants (0 total): 
	Single Pols (1 total): 121e
No description has been provided for this image
Node 10:
	Antpols (1 total): 92e
	Whole Ants (0 total): 
	Single Pols (1 total): 92e
No description has been provided for this image
Node 18:
	Antpols (1 total): 202n
	Whole Ants (0 total): 
	Single Pols (1 total): 202n
No description has been provided for this image

Redcal chi^2: (115 antpols across 93 antennas)

These antennas have been idenfied as not redundantly calibrating well, even after passing the above checks.

All Bad Antpols: 9n, 10n, 16n, 21n, 22n, 33n, 34n, 46n, 49n, 80n, 92n, 97n, 106n, 110e, 114n, 117e, 117n, 124n, 125n, 126e, 126n, 127e, 127n, 128n, 129n, 131e, 132n, 133n, 134e, 134n, 135n, 136e, 136n, 138n, 139n, 140e, 140n, 141n, 143n, 144e, 144n, 145e, 146n, 150n, 152n, 154e, 154n, 155e, 155n, 159n, 160n, 161e, 162e, 162n, 163e, 163n, 164e, 164n, 165e, 165n, 166e, 166n, 167n, 168n, 172n, 173e, 173n, 174e, 174n, 175e, 179n, 182n, 183e, 184n, 185e, 185n, 186e, 186n, 187e, 187n, 188e, 189n, 190n, 193n, 195e, 197n, 200n, 201n, 202e, 204e, 204n, 205n, 206e, 206n, 207n, 210n, 213n, 214n, 215n, 216n, 217n, 220n, 222n, 223n, 225n, 226n, 227n, 228n, 229n, 231e, 231n, 232n, 239n, 252n, 267n

Node 1:
	Antpols (1 total): 16n
	Whole Ants (0 total): 
	Single Pols (1 total): 16n
Node 2:
	Antpols (4 total): 9n, 10n, 21n, 33n
	Whole Ants (0 total): 
	Single Pols (4 total): 9n, 10n, 21n, 33n
Node 5:
	Antpols (1 total): 46n
	Whole Ants (0 total): 
	Single Pols (1 total): 46n
Node 6:
	Antpols (3 total): 22n, 34n, 49n
	Whole Ants (0 total): 
	Single Pols (3 total): 22n, 34n, 49n
Node 7:
	Antpols (3 total): 117e, 117n, 138n
	Whole Ants (1 total): 117
	Single Pols (1 total): 138n
Node 9:
	Antpols (5 total): 106n, 124n, 125n, 126e, 126n
	Whole Ants (1 total): 126
	Single Pols (3 total): 106n, 124n, 125n
Node 10:
	Antpols (6 total): 92n, 110e, 127e, 127n, 128n, 129n
	Whole Ants (1 total): 127
	Single Pols (4 total): 92n, 110e, 128n, 129n
Node 11:
	Antpols (8 total): 80n, 97n, 114n, 131e, 132n, 133n, 134e, 134n
	Whole Ants (1 total): 134
	Single Pols (6 total): 80n, 97n, 114n, 131e, 132n, 133n
Node 12:
	Antpols (6 total): 135n, 136e, 136n, 155e, 155n, 179n
	Whole Ants (2 total): 136, 155
	Single Pols (2 total): 135n, 179n
Node 13:
	Antpols (11 total): 139n, 140e, 140n, 141n, 159n, 160n, 161e, 162e, 162n, 182n, 183e
	Whole Ants (2 total): 162, 140
	Single Pols (7 total): 139n, 141n, 159n, 160n, 161e, 182n, 183e
Node 14:
	Antpols (20 total): 143n, 144e, 144n, 145e, 146n, 163e, 163n, 164e, 164n, 165e, 165n, 166e, 166n, 184n, 185e, 185n, 186e, 186n, 187e, 187n
	Whole Ants (8 total): 163, 164, 165, 166, 144, 185, 186, 187
	Single Pols (4 total): 143n, 145e, 146n, 184n
Node 15:
	Antpols (6 total): 150n, 167n, 168n, 188e, 189n, 190n
	Whole Ants (0 total): 
	Single Pols (6 total): 150n, 167n, 168n, 188e, 189n, 190n
Node 16:
	Antpols (10 total): 152n, 154e, 154n, 172n, 173e, 173n, 174e, 174n, 193n, 213n
	Whole Ants (3 total): 154, 173, 174
	Single Pols (4 total): 152n, 172n, 193n, 213n
Node 17:
	Antpols (4 total): 197n, 215n, 216n, 217n
	Whole Ants (0 total): 
	Single Pols (4 total): 197n, 215n, 216n, 217n
Node 18:
	Antpols (6 total): 200n, 201n, 202e, 220n, 222n, 239n
	Whole Ants (0 total): 
	Single Pols (6 total): 200n, 201n, 202e, 220n, 222n, 239n
Node 19:
	Antpols (9 total): 204e, 204n, 205n, 206e, 206n, 207n, 223n, 225n, 226n
	Whole Ants (2 total): 204, 206
	Single Pols (5 total): 205n, 207n, 223n, 225n, 226n
Node 20:
	Antpols (4 total): 210n, 227n, 228n, 229n
	Whole Ants (0 total): 
	Single Pols (4 total): 210n, 227n, 228n, 229n
Node 21:
	Antpols (6 total): 175e, 195e, 214n, 231e, 231n, 232n
	Whole Ants (1 total): 231
	Single Pols (4 total): 175e, 195e, 214n, 232n
Node 22:
	Antpols (2 total): 252n, 267n
	Whole Ants (0 total): 
	Single Pols (2 total): 252n, 267n

Full-Day Visualizations¶

In [27]:
def classification_plot(col):
    class_array = classification_array(col)
    plt.figure(figsize=(12, len(ants) / 10), dpi=100)
    plt.imshow(class_array.T, aspect='auto', interpolation='none', cmap='RdYlGn', vmin=0, vmax=2,
               extent=[jds[0] - np.floor(jds[0]), jds[-1] - np.floor(jds[0]), len(ants), 0])
    plt.xlabel(f'JD - {int(jds[0])}')
    plt.yticks(ticks=np.arange(.5, len(ants)+.5), labels=[ant for ant in ants], fontsize=6)
    plt.ylabel('Antenna Number (East First, Then North)')
    plt.gca().tick_params(right=True, top=True, labelright=True, labeltop=True)
    plt.tight_layout()
    plt.title(f'{col}: Green is "good", Yellow is "suspect", Red is "bad"')

Figure 1: Per-File Overall Antenna Classification Summary¶

This "big green board" shows the overall (i.e. after redundant calibration) classification of antennas on a per-file basis. This is useful for looking at time-dependent effects across the array. While only antenna numbers are labeled, both polarizations are shown, first East then North going down, above and below the antenna's tick mark.

In [28]:
classification_plot('Antenna Class')