Full Day Systematics Inspection¶

by Tyler Cox and Josh Dillon, last updated July 20, 2024

This notebooks is designed to inspect the full day delay spectra for a small number of redundantly-averaged baselines, by inpainting in frequency and time, and performing delay filtering, cross-talk filtering, and main-beam fringe rate filtering. It is based on a similar notebook written by Josh Dillon for H1C analysis.

More specifically, it looks at 1-unit (i.e. 14.6 m) EW baselines, 2-unit EW baselines, 4-unit EW baselines, and one inter-sector baseline. This is done for both polarizations (and eventually for Pseudo-Stokes I and Q). We look at delay-spectrum waterfalls vs. LST, delay-spectrum waterfalls vs. fringe-rate, and averaged delay-spectra for these baselines. Those spectra are plotted for two wide bands, one below FM and one above FM.

This notebook is divided into four sections:

• Section 1: Time + Frequency Inpainting of Redundantly Averaged Calibrated Visibilities¶

• Section 2: Delay-Filter and Cross-Talk Filter Redundantly-Averaged Visibilities¶

• Section 3: Form Psuedo-Stokes I + Q¶

• Section 4: Main-Beam Fringe-Rate Filter¶

In [1]:
import os
os.environ['HDF5_USE_FILE_LOCKING'] = 'FALSE'
import h5py
import hdf5plugin  # REQUIRED to have the compression plugins available
import glob
import uvtools
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from copy import deepcopy
from pyuvdata import uvbeam, uvdata
from hera_filters import dspec
from hera_cal import io, frf, vis_clean, redcal, utils
from hera_cal.datacontainer import DataContainer, RedDataContainer
from IPython.display import display, HTML

%matplotlib inline
display(HTML("<style>.container { width:100% !important; }</style>"))
_ = np.seterr(all='ignore')  # get rid of red warnings
%config InlineBackend.figure_format = 'retina'
In [2]:
# Get file names
SUM_FILE = os.environ.get("SUM_FILE", None)
#SUM_FILE = '/lustre/aoc/projects/hera/h6c-analysis/IDR2/2459866/zen.2459869.25282.sum.uvh5'
RED_AVG_SUFFIX = os.environ.get("RED_AVG_SUFFIX", "sum.smooth_calibrated.red_avg.uvh5")

# Arguements for delay-filtering, fringe-rate filtering, cross-talk subtraction, and inpainting
XTALK_FR = float(os.environ.get("XTALK_FR", 0.025)) # Fringe rate half-width used for fringe rate filtering
FILT_MIN_DLY = float(os.environ.get("FILT_MIN_DLY", 150.)) # minimum delay for delay-filter in units of ns
INPAINT_MIN_DLY = float(os.environ.get("INPAINT_MIN_DLY", 500.)) # minimum delay for inpainting in units of ns
INPAINT_REGULARIZATION = float(os.environ.get("INPAINT_REGULARIZATION", 1e-5)) # reasonable values are between 1e-2 and 1e-5
STANDOFF = float(os.environ.get("STANDOFF", 50.)) # additional standoff added to min_dly for delay-filter in units of ns
INPAINT_FR = float(os.environ.get("INPAINT_FR", 2.5)) # Fringe-rate half-width in mHz for time inpainting
EIGENVAL_CUTOFF = float(os.environ.get("EIGENVAL_CUTOFF", 1e-12))

# Flag settings to get delay transform regions
FM_LOW_FREQ = float(os.environ.get("FM_LOW_FREQ", 87.5)) # in MHz
FM_HIGH_FREQ = float(os.environ.get("FM_HIGH_FREQ", 108.0)) # in MHz

# Maximum number of contiguous frequency channels in a time integration to attempt to inpaint over
# If number of contiguous flags is greater than this value, flagged channels will remain flagged
# and will attempt to be inpainted over along the time axis
MAX_CONTIGUOUS_FLAGS = int(os.environ.get("MAX_CONTIGUOUS_FLAGS", 20))

# Remove this number of channels on either side of the below/above FM bands to exclude from delay spectrum plots
SPECTRUM_CHAN_BUFFER = int(os.environ.get("SPECTRUM_CHAN_BUFFER", 25))

# Is the input LST-binned
IS_LST_BINNED = os.environ.get("IS_LST_BINNED", "FALSE").upper() == "TRUE"

for setting in ['XTALK_FR', 'FILT_MIN_DLY', 'INPAINT_MIN_DLY', 'STANDOFF', 'INPAINT_FR', 'EIGENVAL_CUTOFF', 
                'FM_LOW_FREQ', 'FM_HIGH_FREQ', 'MAX_CONTIGUOUS_FLAGS', 'SPECTRUM_CHAN_BUFFER', 'IS_LST_BINNED']:
        print(f'{setting} = {eval(setting)}')
XTALK_FR = 0.025
FILT_MIN_DLY = 150.0
INPAINT_MIN_DLY = 500.0
STANDOFF = 50.0
INPAINT_FR = 2.5
EIGENVAL_CUTOFF = 1e-12
FM_LOW_FREQ = 87.5
FM_HIGH_FREQ = 108.0
MAX_CONTIGUOUS_FLAGS = 20
SPECTRUM_CHAN_BUFFER = 25
IS_LST_BINNED = False
In [3]:
sum_glob = os.path.join(os.path.dirname(SUM_FILE), "*" + RED_AVG_SUFFIX)
red_avg_files = sorted(glob.glob(sum_glob))
print(f'Found {len(red_avg_files)} *.{RED_AVG_SUFFIX} files starting with {red_avg_files[0]}.')
Found 174 *.sum.smooth_calibrated.red_avg.uvh5 files starting with /mnt/sn1/data2/2460846/zen.2460846.21085.sum.smooth_calibrated.red_avg.uvh5.
In [4]:
# Select baselines for plotting
for i in range(len(red_avg_files) // 2):
    hd = io.HERADataFastReader(red_avg_files[(len(red_avg_files) // 2) + i])
    bls_to_plot = []

    # Find 1, 2, and 4 units EW auto-pol baselines 
    for bl in hd.bls:
        if utils.split_pol(bl[2])[0] == utils.split_pol(bl[2])[1]:
            bl_vec = (hd.antpos[bl[1]] - hd.antpos[bl[0]])
            if (np.abs(bl_vec[1]) < 1) and int(np.round(bl_vec[0] / 14.6)) in [1, 2, 4]:
                bls_to_plot.append(bl)

    # Get intersector baseline
    _, _, nsamples = hd.read()
    nsamples = RedDataContainer(nsamples, antpos=hd.antpos)
    # try a bunch of possible intersector baselines, hoping one will work
    for ant2 in list(range(226, 233)) + list(range(207, 215)) + list(range(187, 196)):
        if ((144, ant2, 'ee') in nsamples) and ((144, ant2, 'nn') in nsamples):
            if (np.median(nsamples[(144, ant2, 'nn')]) > 0) & (np.median(nsamples[(144, ant2, 'ee')]) > 1):
                bls_to_plot.append(nsamples.get_ubl_key((144, ant2, 'nn')))
                bls_to_plot.append(nsamples.get_ubl_key((144, ant2, 'ee')))
                break
    if len(bls_to_plot) >= 8:
        break

# Identify indices
FM_LOW_FREQ_IND = np.argmin(np.abs(hd.freqs - FM_LOW_FREQ * 1e6))
FM_HIGH_FREQ_IND = np.argmin(np.abs(hd.freqs - FM_HIGH_FREQ * 1e6))
In [5]:
hd = io.HERADataFastReader(red_avg_files)
d, f, n = hd.read(pols=['nn', 'ee'], bls=bls_to_plot)
In [6]:
# Create a truncated version of the data to deal with edge times that are flagged
data = deepcopy(d)
flags = deepcopy(f)
nsamples = deepcopy(n)

# Identify unflagged edge channels
unflagged_chans = np.where(~np.all(flags[bls_to_plot[0]], axis=1))[0]
inds = np.arange(np.min(unflagged_chans), np.max(unflagged_chans) + 1)

# Fix data
for bl in data:
    data[bl] = d[bl][inds]
    flags[bl] = f[bl][inds]
    nsamples[bl] = n[bl][inds]
    
# Fix metadata
data.times = d.times[inds]
data.lsts = d.lsts[inds]

Section 1: Time + Frequency Inpainting of Redundantly Averaged Calibrated Visibilities¶

In [7]:
unit = int(np.round(np.linalg.norm(data.antpos[bls_to_plot[0][1]] - data.antpos[bls_to_plot[0][0]]) / 14.6, 1))
display(HTML(f'<h2>Figure 1: Amplitude and Phase of Calibrated {unit}-unit EW Redundantly-Averaged Baseline</h2>'))

# Get the LSTs from the data
lsts_unwrapped = np.where(data.lsts > data.lsts[-1], data.lsts - 2 * np.pi, data.lsts) * 12 / np.pi  # in hours
extent = [data.freqs[0] / 1e6, data.freqs[-1] / 1e6, lsts_unwrapped[-1], lsts_unwrapped[0]]

if not IS_LST_BINNED:
    fig, axs = plt.subplots(2, 2, figsize=(18, 14), sharex=True, sharey=True, gridspec_kw={'hspace': .03, 'wspace': .03})
else:
    fig, axs = plt.subplots(2, 3, figsize=(18, 14), sharex=True, sharey=True, gridspec_kw={'hspace': .03, 'wspace': .03})
    
fig.subplots_adjust(hspace=0.1, wspace=0.1)

# Plot the amplitude of ee and nn
im1 = axs[0, 0].imshow(np.where(flags[bls_to_plot[0]], np.nan, np.abs(data[bls_to_plot[0]])), aspect='auto', interpolation='none',
                   norm=matplotlib.colors.LogNorm(), cmap='inferno', extent=extent)
axs[1, 0].imshow(np.where(flags[bls_to_plot[1]], np.nan, np.abs(data[bls_to_plot[1]])), aspect='auto', interpolation='none',
                   norm=matplotlib.colors.LogNorm(vmin=im1.get_clim()[0], vmax=im1.get_clim()[1]), cmap='inferno', extent=extent)

# Plot the phase of ee and nn
im2 = axs[0, 1].imshow(
    np.where(flags[bls_to_plot[0]], np.nan, np.angle(data[bls_to_plot[0]])), 
    aspect='auto', cmap='twilight', interpolation='None', extent=extent,
    vmin=-np.pi, vmax=np.pi
)
axs[1, 1].imshow(
    np.where(flags[bls_to_plot[1]], np.nan, np.angle(data[bls_to_plot[1]])), 
    aspect='auto', cmap='twilight', interpolation='None', extent=extent,
    vmin=-np.pi, vmax=np.pi
)

fig.colorbar(im1, ax=axs[:, 0], label='$|V_{ij}|$ (Jy)', location='top', pad=0.01)
fig.colorbar(im2, ax=axs[:, 1], label='Angle($V_{ij})$ (radians)', location='top', pad=0.01)

if IS_LST_BINNED:
    # Plot the amplitude of ee and nn
    im3 = axs[0, 2].imshow(np.where(flags[bls_to_plot[0]], np.nan, nsamples[bls_to_plot[0]]), aspect='auto', interpolation='none',
                       cmap='viridis', extent=extent)
    axs[1, 2].imshow(np.where(flags[bls_to_plot[1]], np.nan, nsamples[bls_to_plot[1]]), aspect='auto', interpolation='none',
                       vmin=im3.get_clim()[0], vmax=im3.get_clim()[1], cmap='viridis', extent=extent)
    fig.colorbar(im3, ax=axs[:, 2], label='Number of Samples', location='top', pad=0.01)
    
    bls_for_labeling = [bls_to_plot[0][2]] * 3 + [bls_to_plot[1][2]] * 3
else:
    bls_for_labeling = [bls_to_plot[0][2]] * 2 + [bls_to_plot[1][2]] * 2

for ax, pol in zip(axs.ravel(), bls_for_labeling):
    ax.text(0.03, 0.97, f"{unit}-unit EW ({pol})", 
             horizontalalignment='left', verticalalignment='top', 
             color='black', transform=ax.transAxes, fontsize=12, 
             bbox=dict(facecolor='w', alpha=.7, boxstyle='round'))
    
for i in range(axs.shape[1]):
    axs[1, i].set_xlabel('Frequency (MHz)')

for i in range(axs.shape[0]):
    axs[i, 0].set_ylabel('LST (hours)')

plt.tight_layout()

Figure 1: Amplitude and Phase of Calibrated 1-unit EW Redundantly-Averaged Baseline

This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.
No description has been provided for this image
In [8]:
def get_flagged_regions(flags, max_flagged_values=25):
    new_flags = np.zeros_like(flags)
    
    for i in range(flags.shape[0]):
        if np.all(flags[i]):
            new_flags[i] = True
        elif np.all(flags[i, low_band]) ^ np.all(flags[i, high_band]):
            new_flags[i, :] = True
            new_flags[i, high_band] = np.all(flags[i, high_band])
            new_flags[i, low_band] = np.all(flags[i, low_band])
        else:
            z = np.concatenate(([False], flags[i], [False]))
            starts = np.flatnonzero(~z[:-1] & z[1:])   
            ends = np.flatnonzero(z[:-1] & ~z[1:])
            for start, end in zip(starts, ends):
                if np.abs(end - start) > max_flagged_values:
                    new_flags[i, start:end] = True
                
    return new_flags

def sym_log_norm(to_plot):
    '''Shortcut for symmetric sym log norm.'''
    return matplotlib.colors.SymLogNorm(10, vmin=-np.nanmax(np.abs(to_plot)), vmax=np.nanmax(np.abs(to_plot)))
In [9]:
# Copy data
data_inpaint = deepcopy(data)
data_delay_filt = deepcopy(data)

# Peform delay filter separately above and below FM
FM_ind = np.argmin(np.abs(hd.freqs - 100e6))
unflagged_chans = np.argwhere(~np.all([np.all(flags[bl], axis=0) for bl in bls_to_plot], axis=0)).squeeze()
low_band = slice(np.min(unflagged_chans), np.max(unflagged_chans[unflagged_chans < FM_ind]) + 1)
high_band = slice(np.min(unflagged_chans[unflagged_chans > FM_ind]), np.max(unflagged_chans) + 1)

delay_bounds = {}
cache = {}

for inpaint, min_dly in zip([True, False], [INPAINT_MIN_DLY, FILT_MIN_DLY]):
    for bl in data:
        if np.all(data[bl] == 0.0) and np.all(flags[bl]):
            # don't bother delay filtering all 0s.
            continue

        wgts = np.where(flags[bl], 0, 1)

        # calculate filter properties
        bl_vec = (hd.antpos[bl[1]] - hd.antpos[bl[0]])
        bl_len = np.linalg.norm(bl_vec[:2]) / vis_clean.constants.c.value
        filter_centers, filter_half_widths = vis_clean.gen_filter_properties(ax='freq', horizon=1, standoff=STANDOFF, 
                                                                             min_dly=min_dly, bl_len=bl_len)
        delay_bounds[bl[:2]] = (filter_centers[0] - filter_half_widths[0], filter_centers[0] + filter_half_widths[0])

        # run delay filter for each band individually
        d_mdl = np.zeros_like(data[bl])
        for band in [low_band, high_band]:
            d_mdl[:, band], _, info = dspec.fourier_filter(hd.freqs[band], data[bl][:, band], wgts=wgts[:, band], filter_centers=filter_centers, 
                                                           filter_half_widths=filter_half_widths, mode='dpss_solve', 
                                                           ridge_alpha=(INPAINT_REGULARIZATION if inpaint else 0), fit_intercept=inpaint,
                                                           eigenval_cutoff=[EIGENVAL_CUTOFF], max_contiguous_edge_flags=len(hd.freqs[band]), cache=cache)
        if not inpaint:
            data_delay_filt[bl] = np.where(flags[bl], 0, data_inpaint[bl] - d_mdl)
        elif inpaint:
            data_inpaint[bl] = np.where(flags[bl], d_mdl, data_inpaint[bl])
            _flags = get_flagged_regions(flags[bl], max_flagged_values=MAX_CONTIGUOUS_FLAGS)
            _wgts = np.where(_flags, 0, 1)

            # now inpaint in time
            d_mdl = np.zeros_like(data[bl])
            for band in [low_band, high_band]:
                d_mdl[:, band], _, info = dspec.fourier_filter(data.times * 24 * 60 * 60, data_inpaint[bl][:, band], wgts=_wgts[:, band], filter_centers=filter_centers, 
                                                               filter_half_widths=[INPAINT_FR / 1000.], mode='dpss_solve', filter_dims=0, ridge_alpha=INPAINT_REGULARIZATION,
                                                               eigenval_cutoff=[EIGENVAL_CUTOFF], max_contiguous_edge_flags=len(data.times), cache=cache)


            data_inpaint[bl] = np.where(_flags, d_mdl, data_inpaint[bl])
In [10]:
# Indices to use for plotting
low_rng = np.arange(low_band.start + SPECTRUM_CHAN_BUFFER, low_band.stop - SPECTRUM_CHAN_BUFFER, dtype=int)
high_rng = np.arange(high_band.start + SPECTRUM_CHAN_BUFFER, high_band.stop - SPECTRUM_CHAN_BUFFER, dtype=int)
In [11]:
def plot_delay_vs_lst(data, rng, min_dly=FILT_MIN_DLY, vmin=None, vmax=None, title=""):
    
    # Add search-able title to figure
    display(HTML(f'<h2>{title}</h2>'))
    
    # plot in delay space
    fig, axs = plt.subplots(2, 4, figsize=(14,14), sharex=True, sharey=True)

    # Organize baselines
    plot_bls = list(set([bl[:2] for bl in data.keys() if bl[0] != bl[1]]))
    plot_bls = sorted(plot_bls, key=lambda k: np.linalg.norm(data.antpos[k[1]] - data.antpos[k[0]]))
    plot_pols = sorted(list(set([bl[-1] for bl in data.keys()])))

    # Fringe-rates
    lsts_unwrapped = np.where(data.lsts > data.lsts[-1], data.lsts - 2 * np.pi, data.lsts) * 12 / np.pi  # in hours

    for bi, blkey in enumerate(plot_bls):
        for pi, pol in enumerate(plot_pols):
            bl = blkey + (pol, )
            dfft = uvtools.utils.FFT(data[bl][:, rng], axis=1, taper='bh7')
            delays = uvtools.utils.fourier_freqs(hd.freqs[rng]) * 1e9
            to_plot = np.real(dfft)

            # Scale vmin and vmax 
            if bi == 0 and pi == 0: 
                _to_plot = np.copy(to_plot)

            im = axs[pi, bi].imshow(to_plot, interpolation='none', aspect='auto', cmap='bwr', norm=sym_log_norm(_to_plot),
                       extent=[delays[0], delays[-1], lsts_unwrapped[-1], lsts_unwrapped[0]])
            axs[pi, bi].set_xlim([-1499, 1499])

            # Get baseline-lengths
            blvec = data.antpos[bl[0]] - data.antpos[bl[1]]
            bllen = np.linalg.norm(blvec)
            if bi < 3:
                bltype = f"{int(np.round(bllen / 14.6))}-unit EW" 
            else:
                bltype = f"{np.abs(blvec[0]):.0f} m {'E' if blvec[0] > 0 else 'W'}, {np.abs(blvec[1]):.0f} m {'N' if blvec[1] > 0 else 'S'}"

            axs[pi, bi].text(0.05, 0.98, f"{bltype} ({pol})\n{np.round(data.freqs[rng[0]] / 1e6, 1)}—{np.round(data.freqs[rng[-1]] / 1e6, 1)} MHz", 
                             horizontalalignment='left', verticalalignment='top', 
                             color='black', transform=axs[pi, bi].transAxes, fontsize=12, 
                             bbox=dict(facecolor='w', alpha=.7, boxstyle='round'))

            # Label axes
            if pi == 1:
                axs[pi, bi].set_xlabel('Delay (ns)')
            if bi == 0:
                axs[pi, bi].set_ylabel('LST [hr]')
                
            bl_vec = (hd.antpos[blkey[1]] - hd.antpos[blkey[0]])
            bl_len = np.linalg.norm(bl_vec[:2]) / vis_clean.constants.c.value
            filter_centers, filter_half_widths = vis_clean.gen_filter_properties(
                ax='freq', horizon=1, standoff=STANDOFF, min_dly=min_dly, bl_len=bl_len
            )

            axs[pi, bi].axvline(-filter_half_widths[0] * 1e9, color='k', ls='-.')
            axs[pi, bi].axvline(filter_half_widths[0] * 1e9, color='k', ls='-.')
    
    plt.tight_layout()

    # Colorbar
    fig.subplots_adjust(right=0.9)
    cbar_ax = fig.add_axes([0.92, 0.04, 0.02, 0.95])
    fig.colorbar(im, cax=cbar_ax, label='$|\widetilde{V}_{ij}|$ (Jy)', extend='both')
    return {'vmin': vmin, 'vmax': vmax}
invalid escape sequence '\w'
invalid escape sequence '\w'
invalid escape sequence '\w'
In [12]:
def plot_delay_fringe_rate(data, rng, vmin=None, vmax=None, delay_bounds=None, fringe_bounds=None, title=""):
    
    # Add search-able title to figure
    display(HTML(f'<h2>{title}</h2>'))
    
    # plot in delay space
    fig, axs = plt.subplots(2, 4, figsize=(14, 8), sharex=True, sharey=True)

    # Organize baselines
    plot_bls = list(set([bl[:2] for bl in data.keys() if bl[0] != bl[1]]))
    plot_bls = sorted(plot_bls, key=lambda k: np.linalg.norm(data.antpos[k[1]] - data.antpos[k[0]]))
    plot_pols = sorted(list(set([bl[-1] for bl in data.keys()])))

    # Fringe-rates
    frates = uvtools.utils.fourier_freqs(data.times * 24 * 60 * 60) * 1000

    for bi, blkey in enumerate(plot_bls):
        for pi, pol in enumerate(plot_pols):
            bl = blkey + (pol, )
            dfft = uvtools.utils.FFT(data[bl][:, rng], axis=1, taper='bh7')
            delays = uvtools.utils.fourier_freqs(hd.freqs[rng]) * 1e9
            dfft2 = uvtools.utils.FFT(dfft, axis=0, taper='bh7')

            # Scale vmin and vmax 
            if bi == 0 and pi == 0: 
                vmin = np.median(np.abs(dfft2)) if vmin is None else vmin
                vmax = np.max(np.abs(dfft2)) if vmax is None else vmax

            im = axs[pi, bi].imshow(np.abs(dfft2), interpolation='none', aspect='auto', cmap='turbo', 
                                    norm=matplotlib.colors.LogNorm(vmin=vmin, vmax=vmax),
                                    extent=[delays[0], delays[-1], frates[-1], frates[0]])
            axs[pi, bi].set_xlim([-799, 799])
            axs[pi, bi].set_ylim([-5, 5])

            # Get baseline-lengths
            blvec = data.antpos[bl[0]] - data.antpos[bl[1]]
            bllen = np.linalg.norm(blvec)
            if bi < 3:
                bltype = f"{int(np.round(bllen / 14.6))}-unit EW" 
            else:
                bltype = f"{np.abs(blvec[0]):.0f} m {'E' if blvec[0] > 0 else 'W'}, {np.abs(blvec[1]):.0f} m {'N' if blvec[1] > 0 else 'S'}"

            axs[pi, bi].text(0.04, 0.96, f"{bltype} ({pol})\n{np.round(data.freqs[rng[0]] / 1e6, 1)}—{np.round(data.freqs[rng[-1]] / 1e6, 1)} MHz", 
                             horizontalalignment='left', verticalalignment='top', 
                             color='black', transform=axs[pi, bi].transAxes, fontsize=12, 
                             bbox=dict(facecolor='w', alpha=.7, boxstyle='round'))

            # Label axes
            if pi == 1:
                axs[pi, bi].set_xlabel('Delay (ns)')
            if bi == 0:
                axs[pi, bi].set_ylabel('Fringe Rate [mHz]')
                
            if delay_bounds:
                axs[pi, bi].axvline(delay_bounds[bl[:2]][0] * 1e9, color='white', ls='-')
                axs[pi, bi].axvline(delay_bounds[bl[:2]][1] * 1e9, color='white', ls='-')
            if fringe_bounds:
                axs[pi, bi].axhline(fringe_bounds[bl[:2]][0], color='white', ls='-.')
                axs[pi, bi].axhline(fringe_bounds[bl[:2]][1], color='white', ls='-.')

    plt.tight_layout()

    # Colorbar
    fig.subplots_adjust(right=0.9)
    cbar_ax = fig.add_axes([0.92, 0.04, 0.02, 0.95])
    fig.colorbar(im, cax=cbar_ax, label='$|\widetilde{V}_{ij}|$ (Jy)', extend='both')
    
    return {'vmin': vmin, 'vmax': vmax}
invalid escape sequence '\w'
invalid escape sequence '\w'
invalid escape sequence '\w'
In [13]:
plot_delay_vs_lst(
    data_inpaint, low_rng, min_dly=INPAINT_MIN_DLY,
    title=f'Figure 2: Real Part of Redundantly-Averaged, DPSS Time + Frequency Inpainted, \
    Delay Transformed, {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz'
);

Figure 2: Real Part of Redundantly-Averaged, DPSS Time + Frequency Inpainted, Delay Transformed, 50.0—84.2 MHz

No description has been provided for this image
In [14]:
plot_delay_vs_lst(
    data_inpaint, high_rng, min_dly=INPAINT_MIN_DLY,
    title=f'Figure 3: Real Part of Redundantly-Averaged, DPSS Time + Frequency Inpainted, \
    Delay Transformed, {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz'
);

Figure 3: Real Part of Redundantly-Averaged, DPSS Time + Frequency Inpainted, Delay Transformed, 111.4—230.1 MHz

No description has been provided for this image
In [15]:
low_band_meta = plot_delay_fringe_rate(
    data_inpaint, low_rng, title=f'Figure 4: Redundantly-Averaged, DPSS Time + Frequency Inpainted,\
    Delay + Fringe Transformed Visibilities, {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz'
)

Figure 4: Redundantly-Averaged, DPSS Time + Frequency Inpainted, Delay + Fringe Transformed Visibilities, 50.0—84.2 MHz

No description has been provided for this image
In [16]:
high_band_meta = plot_delay_fringe_rate(
    data_inpaint, high_rng, title=f'Figure 5: Redundantly-Averaged, DPSS Time + Frequency Inpainted, \
    Delay + Fringe Transformed Visibilities, {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz'
)

Figure 5: Redundantly-Averaged, DPSS Time + Frequency Inpainted, Delay + Fringe Transformed Visibilities, 111.4—230.1 MHz

No description has been provided for this image

Section 2: Delay-Filter and Cross-Talk Filter Redundantly-Averaged Visibilities¶

In [17]:
data_xtalk_filt = deepcopy(data_delay_filt)

cache = {}
for bl in data_delay_filt:
    # don't bother delay filtering all 0s.
    if np.all(data_delay_filt[bl] == 0.0) and np.all(flags[bl]):
        continue

    # run delay filter for each band individually
    d_res = np.zeros_like(data_delay_filt[bl])

    # Get weights
    wgts = (~flags[bl]).astype(float)

    for band in [low_band, high_band]:
        _, d_res[:, band], info = dspec.fourier_filter(data.times * 24 * 60 * 60, data_delay_filt[bl][:, band], 
                                                       wgts=wgts[:, band], filter_centers=filter_centers, 
                                                       filter_half_widths=[XTALK_FR / 1000], mode='dpss_solve', 
                                                       eigenval_cutoff=[EIGENVAL_CUTOFF], max_contiguous_edge_flags=len(data.times), cache=cache, filter_dims=0)

    data_xtalk_filt[bl] = d_res
In [18]:
_ = plot_delay_vs_lst(
    data_xtalk_filt, low_rng,
    title=f'Figure 6: Real Part of Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, \
    Delay Transformed Visibility, {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz'
)

Figure 6: Real Part of Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, Delay Transformed Visibility, 50.0—84.2 MHz

No description has been provided for this image
In [19]:
_ = plot_delay_vs_lst(
    data_xtalk_filt, high_rng,
    title=f'Figure 7: Real Part of Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, \
    Delay Transformed Visibility, {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz'
)

Figure 7: Real Part of Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, Delay Transformed Visibility, 111.4—230.1 MHz

No description has been provided for this image
In [20]:
low_band_meta = plot_delay_fringe_rate(
    data_xtalk_filt, low_rng, delay_bounds=delay_bounds, 
    title=f'Figure 8: Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, \
    Delay + Fringe Transformed Visibility, {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz'
)

Figure 8: Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, Delay + Fringe Transformed Visibility, 50.0—84.2 MHz

No description has been provided for this image
In [21]:
high_band_meta = plot_delay_fringe_rate(
    data_xtalk_filt, high_rng, delay_bounds=delay_bounds,
    title=f'Figure 9: Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, \
    Delay + Fringe Transformed Visibility, {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz'
)

Figure 9: Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, Delay + Fringe Transformed Visibility, 111.4—230.1 MHz

No description has been provided for this image
In [22]:
def calculate_avg_norm_spectra(dfft, flags, nsamples):
    '''Calculates incoherently-averaged spectrum, using ses flags and frequency-averaged nsamples as weights.'''   
    wgts = np.where(np.all(flags, axis=1, keepdims=True), np.nan, np.sum(nsamples, axis=1, keepdims=True))
    avg_norm_spectra = np.nanmean(np.where(np.all(flags, axis=1, keepdims=True), np.nan, np.abs(dfft) * wgts), axis=0) / np.nanmean(wgts)
    return avg_norm_spectra

def coherently_average_visibilities(dc_list, flags, nsamples, rng, nint=20):
    """
    """
    avg_vis = []
    delays = uvtools.utils.fourier_freqs(dc_list[0].freqs[rng]) * 1e9
    flags_for_avg = np.repeat(np.all(_flags, axis=1, keepdims=True), hd.freqs.shape[0], axis=1)
    
    for dc in dc_list:
        avg_delay_spec = {}
        for bl in dc.keys():
            bl_vec = (hd.antpos[bl[1]] - hd.antpos[bl[0]])

            # Coherently average
            ad, af, an, _, _ = frf.timeavg_waterfall(
                dc[bl], nint, nsamples=nsamples[bl], flags=flags_for_avg,
                rephase=True, lsts=dc.lsts, freqs=dc.freqs, bl_vec=bl_vec,
                extra_arrays=dict(times=dc.times), wgt_by_nsample=True, verbose=False
            )

            # Delay Transform
            dfft_avg = uvtools.utils.FFT(ad[:, rng], axis=1, taper='bh7')

            # Incoherently Average - Cohorently Averaged Visibilities
            avg_delay_spec[bl] = calculate_avg_norm_spectra(
                dfft_avg, af[:, rng], an[:, rng]
            )
            
        avg_vis.append(avg_delay_spec)
        
    return delays, avg_vis

def plot_coherently_averaged_1d(delays, dc_list, plot_labels, rng, min_dly=FILT_MIN_DLY, ymin=3e-1, ymax=3e4, title=""):
    # Add search-able title to figure
    display(HTML(f'<h2>{title}</h2>'))
    
    fig, axs = plt.subplots(2, 4, figsize=(14, 10), sharex=True, sharey=True, gridspec_kw={'wspace': 0, 'hspace': 0})

    plot_bls = list(set([bl[:2] for bl in dc_list[0].keys() if bl[0] != bl[1]]))
    plot_bls = sorted(plot_bls, key=lambda k: np.linalg.norm(data.antpos[k[1]] - data.antpos[k[0]]))
    plot_pols = sorted(list(set([bl[-1] for bl in dc_list[0].keys()])))
    
    # Lists for setting vmin and vmax
    ymins = []
    ymaxs = []
        
    for bi, blkey in enumerate(plot_bls):
        for pi, pol in enumerate(plot_pols):
            
            # Store plot output for legend
            plot_objs = []
            
            bl = blkey + (pol, )
            for fi, avg_filt in enumerate(dc_list):
                line = axs[pi, bi].semilogy(delays, avg_filt[bl], label=plot_labels[fi])
                plot_objs.append(line[0])
                
                # Get vmins and maxes
                ymins.append(np.median(avg_filt[bl]))
                ymaxs.append(np.max(avg_filt[bl]))

            axs[pi, bi].set_xlim([-2900, 2900])
            axs[pi, bi].grid()

            # Set widths
            bl_vec = (hd.antpos[bl[1]] - hd.antpos[bl[0]])
            bl_len = np.linalg.norm(bl_vec[:2]) / vis_clean.constants.c.value
            filter_centers, filter_half_widths = vis_clean.gen_filter_properties(ax='freq', horizon=1, standoff=STANDOFF, 
                                                                                 min_dly=min_dly, bl_len=bl_len)
            axs[pi, bi].axvline(-filter_half_widths[0] * 1e9, color='k', ls=':')
            fw_line = axs[pi, bi].axvline(filter_half_widths[0] * 1e9, color='k', ls=':', label='Filter Width')
            plot_objs.append(fw_line)

            axs[pi, bi].axvline(-bl_len * 1e9, color='k', ls='-', lw=0.75)
            horizon_line = axs[pi, bi].axvline(bl_len * 1e9, color='k', ls='-', label='Horizon', lw=0.75)
            plot_objs.append(horizon_line)

            # Get baseline-lengths
            blvec = data.antpos[bl[0]] - data.antpos[bl[1]]
            bllen = np.linalg.norm(blvec)
            if bi < 3:
                bltype = f"{int(np.round(bllen / 14.6))}-unit EW" 
            else:
                bltype = f"{np.abs(blvec[0]):.0f} m {'E' if blvec[0] > 0 else 'W'}, {np.abs(blvec[1]):.0f} m {'N' if blvec[1] > 0 else 'S'}"

            axs[pi, bi].text(0.05, 0.97, f"{bltype} ({pol})\n{np.round(data.freqs[rng[0]] / 1e6, 1)}—{np.round(data.freqs[rng[-1]] / 1e6, 1)} MHz", 
                             horizontalalignment='left', verticalalignment='top', 
                             color='black', transform=axs[pi, bi].transAxes, fontsize=12, 
                             bbox=dict(facecolor='w', alpha=.7, boxstyle='round'))

            if bi == 0:
                axs[pi, bi].set_ylabel(r'$|\widetilde{V}| \ [\rm Jy]$')
            if pi == 1:
                axs[pi, bi].set_xlabel(r'$\tau \ [\rm ns]$')
                
    
    for bi, blkey in enumerate(plot_bls):
        for pi, pol in enumerate(plot_pols):
            axs[pi, bi].set_ylim([np.min(ymins) * 0.1, np.max(ymaxs) * 10])

    fig.legend([pobj for pobj in plot_objs], [pobj._label for pobj in plot_objs], loc='upper center', ncol=len(plot_objs), 
               bbox_to_anchor=(0.5, 1.025))
    plt.tight_layout()
    plt.show()
    
In [23]:
# Coherently-average visibilities
delays, avg_vis = coherently_average_visibilities(
    [data_inpaint, data_delay_filt, data_xtalk_filt], flags, nsamples, low_rng
)

# Plot coherenetly-averaged visibilities
plot_labels = ['DPSS Inpainted', 'DPSS Delay-Filtered', f'DPSS Delay-Filtered + DPSS Notch-Filtered: {XTALK_FR} mHz']
plot_coherently_averaged_1d(
    delays, avg_vis, plot_labels, low_rng,
    title=f'Figure 10: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged Visibilities,\
    {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz'
)

Figure 10: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged Visibilities, 50.0—84.2 MHz

No description has been provided for this image
In [24]:
# Coherently-average visibilities
delays, avg_vis = coherently_average_visibilities(
    [data_inpaint, data_delay_filt, data_xtalk_filt], flags, nsamples, high_rng
)

# Plot coherenetly-averaged visibilities
plot_labels = ['DPSS Inpainted', 'DPSS Delay-Filtered', f'DPSS Delay-Filtered + DPSS Notch-Filtered: {XTALK_FR} mHz']
v = plot_coherently_averaged_1d(
    delays, avg_vis, plot_labels, high_rng,
    title=f'Figure 11: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged Visibilities,\
    {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz'
)

Figure 11: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged Visibilities, 111.4—230.1 MHz

No description has been provided for this image

Section 3: Form Psuedo-Stokes I + Q¶

In [25]:
# Create dictionaries for polarized data
data_p_xtalk_filt, flags_p_xtalk_filt, nsamples_p_xtalk_filt = {}, {}, {}
data_p_delay_filt, flags_p_delay_filt, nsamples_p_delay_filt = {}, {}, {}
data_p_inpaint, flags_p_inpaint, nsamples_p_inpaint = {}, {}, {}

for bl in data_inpaint.antpairs():
    # Stokes-I - data, flags, namples
    data_p_xtalk_filt[bl + ('pI',)] = (data_xtalk_filt[bl + ('nn',)] + data_xtalk_filt[bl + ('ee',)]) / 2
    data_p_delay_filt[bl + ('pI',)] = (data_delay_filt[bl + ('nn',)] + data_delay_filt[bl + ('ee',)]) / 2
    data_p_inpaint[bl + ('pI',)] = (data_inpaint[bl + ('nn',)] + data_inpaint[bl + ('ee',)]) / 2
    
    flags_p_xtalk_filt[bl + ('pI',)] = flags[bl + ('nn',)] | flags[bl + ('ee',)]
    flags_p_delay_filt[bl + ('pI',)] = flags[bl + ('nn',)] | flags[bl + ('ee',)]
    flags_p_inpaint[bl + ('pI',)] = flags[bl + ('nn',)] | flags[bl + ('ee',)]
    
    nsamples_p_xtalk_filt[bl + ('pI',)] = (nsamples[bl + ('nn',)] + nsamples[bl + ('ee',)]) / 2
    nsamples_p_delay_filt[bl + ('pI',)] = (nsamples[bl + ('nn',)] + nsamples[bl + ('ee',)]) / 2
    nsamples_p_inpaint[bl + ('pI',)] = (nsamples[bl + ('nn',)] + nsamples[bl + ('ee',)]) / 2
    
    # Stokes Q - data, flags, namples
    data_p_xtalk_filt[bl + ('pQ',)] = (data_xtalk_filt[bl + ('ee',)] - data_xtalk_filt[bl + ('nn',)]) / 2
    data_p_delay_filt[bl + ('pQ',)] = (data_delay_filt[bl + ('ee',)] - data_delay_filt[bl + ('nn',)]) / 2
    data_p_inpaint[bl + ('pQ',)] = (data_inpaint[bl + ('ee',)] - data_inpaint[bl + ('nn',)]) / 2
    
    flags_p_xtalk_filt[bl + ('pQ',)] = flags[bl + ('nn',)] | flags[bl + ('ee',)]
    flags_p_delay_filt[bl + ('pQ',)] = flags[bl + ('nn',)] | flags[bl + ('ee',)]
    flags_p_inpaint[bl + ('pQ',)] = flags[bl + ('nn',)] | flags[bl + ('ee',)]
    
    nsamples_p_xtalk_filt[bl + ('pQ',)] = (nsamples[bl + ('nn',)] + nsamples[bl + ('ee',)]) / 2
    nsamples_p_delay_filt[bl + ('pQ',)] = (nsamples[bl + ('nn',)] + nsamples[bl + ('ee',)]) / 2
    nsamples_p_inpaint[bl + ('pQ',)] = (nsamples[bl + ('nn',)] + nsamples[bl + ('ee',)]) / 2
    
# Attach metadata
data_p_xtalk_filt = DataContainer(data_p_xtalk_filt)
data_p_xtalk_filt.times = data.times
data_p_xtalk_filt.freqs = data.freqs
data_p_xtalk_filt.antpos = data.antpos
data_p_xtalk_filt.lsts = data.lsts

data_p_delay_filt = DataContainer(data_p_delay_filt)
data_p_delay_filt.times = data.times
data_p_delay_filt.freqs = data.freqs
data_p_delay_filt.antpos = data.antpos
data_p_delay_filt.lsts = data.lsts

data_p_inpaint = DataContainer(data_p_inpaint)
data_p_inpaint.times = data.times
data_p_inpaint.freqs = data.freqs
data_p_inpaint.antpos = data.antpos
data_p_inpaint.lsts = data.lsts
In [26]:
_ = plot_delay_vs_lst(
    data_p_xtalk_filt, low_rng,
    title=f'Figure 12: Real Part of Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, \
    Delay-Transformed, Psuedo-Stokes I and Q Visibilities, {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz'
)

Figure 12: Real Part of Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, Delay-Transformed, Psuedo-Stokes I and Q Visibilities, 50.0—84.2 MHz

No description has been provided for this image
In [27]:
_ = plot_delay_vs_lst(
    data_p_xtalk_filt, high_rng,
    title=f'Figure 13: Real Part of Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, \
    Delay-Transformed, Psuedo-Stokes I and Q Visibilities, {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz'
)

Figure 13: Real Part of Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, Delay-Transformed, Psuedo-Stokes I and Q Visibilities, 111.4—230.1 MHz

No description has been provided for this image
In [28]:
# TODO: Add extend arrow and horizon lines 
_ = plot_delay_fringe_rate(
    data_p_xtalk_filt, low_rng, delay_bounds=delay_bounds, 
    title=f'Figure 14: Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, \
    Delay + Fringe Transformed, Psuedo-Stokes I and Q Visibilities, {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz',
    **low_band_meta
)

Figure 14: Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, Delay + Fringe Transformed, Psuedo-Stokes I and Q Visibilities, 50.0—84.2 MHz

No description has been provided for this image
In [29]:
_ = plot_delay_fringe_rate(
    data_p_xtalk_filt, high_rng, delay_bounds=delay_bounds,
    title=f'Figure 15: Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, \
    Delay + Fringe Transformed, Psuedo-Stokes I and Q Visibilities, {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz',
    **high_band_meta
)

Figure 15: Redundantly-Averaged, DPSS Delay + Cross-Talk Filtered, Delay + Fringe Transformed, Psuedo-Stokes I and Q Visibilities, 111.4—230.1 MHz

No description has been provided for this image
In [30]:
# Coherently-average visibilities
delays, avg_vis = coherently_average_visibilities(
    [data_p_inpaint, data_p_delay_filt, data_p_xtalk_filt], flags_p_inpaint, nsamples_p_inpaint, low_rng
)

# Plot coherently-averaged visibilities
plot_labels = [
    'DPSS Inpainted', 'DPSS Delay-Filtered', f'DPSS Delay-Filtered + DPSS Notch-Filtered: {XTALK_FR} mHz'
]
plot_coherently_averaged_1d(
    delays, avg_vis, plot_labels, low_rng,
    title=f'Figure 16: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged Visibilities,\
    Psuedo-Stokes I and Q, {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz'
)

Figure 16: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged Visibilities, Psuedo-Stokes I and Q, 50.0—84.2 MHz

No description has been provided for this image
In [31]:
# Coherently-average visibilities
delays, avg_vis = coherently_average_visibilities(
    [data_p_inpaint, data_p_delay_filt, data_p_xtalk_filt], flags_p_inpaint, nsamples_p_inpaint, high_rng
)

# Plot coherenetly-averaged visibilities
plot_labels = [
    'DPSS Inpainted', 'DPSS Delay-Filtered', f'DPSS Delay-Filtered + DPSS Notch-Filtered: {XTALK_FR} mHz'
]
plot_coherently_averaged_1d(
    delays, avg_vis, plot_labels, high_rng,
    title=f'Figure 17: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged Visibilities,\
    Psuedo-Stokes I and Q, {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz'
)

Figure 17: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged Visibilities, Psuedo-Stokes I and Q, 111.4—230.1 MHz

No description has been provided for this image

Section 4: Main-Beam Fringe-Rate Filter¶

In [32]:
# Load one file as pyuvdata object to get metadata
uvd = uvdata.UVData()
uvd.read(red_avg_files[len(red_avg_files) // 2], axis='blt', bls=bls_to_plot)
uvd.use_future_array_shapes()

# Load uvbeam file
uvbeam_file_lustre = "/lustre/aoc/projects/hera/h6c-analysis/IDR2/beams/NF_HERA_Vivaldi_efield_beam_healpix.fits"
uvbeam_file_karoo = "/mnt/sn1/data1/beam_models/NF_HERA_Vivaldi_efield_beam_healpix.fits"
uvb = uvbeam.UVBeam()
try:
    uvb.read(uvbeam_file_lustre)
except:
    uvb.read(uvbeam_file_karoo)
uvb.use_future_array_shapes()

# Extract metadata
dt = np.diff(data.times)[0] * 60 * 60 * 24
nfr = data.times.shape[0]
dfr = np.diff(uvtools.utils.fourier_freqs(dt * np.arange(nfr)))[0] * 1000

# Get fringe rates centers and widths for each baseline
frate_centers, frate_half_widths = frf.get_fringe_rate_limits(uvd=uvd, uvb=uvb, nfr=nfr, dfr=dfr)
frate_bounds = {
    k[:2]: (frate_centers[k] - frate_half_widths[k], frate_centers[k] + frate_half_widths[k]) for k in frate_centers
}
In [33]:
data_beam_filt = deepcopy(data_p_xtalk_filt)
cache = {}
for bl in data_p_xtalk_filt:
    # don't bother delay filtering all 0s.
    if np.all(data_p_xtalk_filt[bl] == 0.0) and np.all(flags[bl]):
        continue

    d_mdl = np.zeros_like(data_p_xtalk_filt[bl])

    # Get weights
    wgts = (~np.repeat(np.all(flags_p_inpaint[bl], axis=1, keepdims=True), data.freqs.shape[0], axis=1)).astype(float)

    # Run main-beam filter for each band individually
    for band in [low_band, high_band]:
        d_mdl[:, band], _, info = dspec.fourier_filter(data.times * 24 * 60 * 60, data_p_xtalk_filt[bl][:, band], 
                                                       wgts=wgts[:, band], filter_centers=[frate_centers[bl[:2] + ('nn',)] / 1000], 
                                                       filter_half_widths=[frate_half_widths[bl[:2] + ('nn',)] / 1000], mode='dpss_solve',
                                                       eigenval_cutoff=[EIGENVAL_CUTOFF], max_contiguous_edge_flags=len(data.times), 
                                                       cache=cache, filter_dims=0)

    data_beam_filt[bl] = d_mdl
In [34]:
_ = plot_delay_vs_lst(
    data_beam_filt, low_rng,
    title=f'Figure 18: Real Part of Redundantly-Averaged, DPSS Delay + Main-Beam Filtered, \
    Delay-Transformed, Psuedo-Stokes I and Q Visibilities, {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz'
)

Figure 18: Real Part of Redundantly-Averaged, DPSS Delay + Main-Beam Filtered, Delay-Transformed, Psuedo-Stokes I and Q Visibilities, 50.0—84.2 MHz

No description has been provided for this image
In [35]:
_ = plot_delay_vs_lst(
    data_beam_filt, high_rng,
    title=f'Figure 19: Real Part of Redundantly-Averaged, DPSS Delay + Main-Beam Filtered, \
    Delay-Transformed, Psuedo-Stokes I and Q Visibilities, {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz'
)

Figure 19: Real Part of Redundantly-Averaged, DPSS Delay + Main-Beam Filtered, Delay-Transformed, Psuedo-Stokes I and Q Visibilities, 111.4—230.1 MHz

No description has been provided for this image
In [36]:
_ = plot_delay_fringe_rate(
    data_beam_filt, low_rng, delay_bounds=delay_bounds, fringe_bounds=frate_bounds,
    title=f'Figure 20: Redundantly-Averaged, DPSS Delay + Cross-Talk + Main-Beam Filtered, \
    Delay + Fringe Transformed, Psuedo-Stokes I and Q Visibilities, {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz',
    **low_band_meta
)

Figure 20: Redundantly-Averaged, DPSS Delay + Cross-Talk + Main-Beam Filtered, Delay + Fringe Transformed, Psuedo-Stokes I and Q Visibilities, 50.0—84.2 MHz

No description has been provided for this image
In [37]:
_ = plot_delay_fringe_rate(
    data_beam_filt, high_rng, delay_bounds=delay_bounds, fringe_bounds=frate_bounds,
    title=f'Figure 21: Redundantly-Averaged, DPSS Delay + Cross-Talk + Main-Beam Filtered, \
    Delay + Fringe Transformed, Psuedo-Stokes I and Q Visibilities, {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz',
    **high_band_meta
)

Figure 21: Redundantly-Averaged, DPSS Delay + Cross-Talk + Main-Beam Filtered, Delay + Fringe Transformed, Psuedo-Stokes I and Q Visibilities, 111.4—230.1 MHz

No description has been provided for this image
In [38]:
# Coherently-average visibilities
delays, avg_vis = coherently_average_visibilities(
    [data_p_inpaint, data_p_delay_filt, data_p_xtalk_filt, data_beam_filt], flags_p_inpaint, nsamples_p_inpaint, low_rng
)

plot_labels = [
    'DPSS Inpainted', 'DPSS Delay-Filtered', 'DPSS Delay + Cross Talk-Filtered', 
    f'DPSS Delay-Filtered + Main-Beam Filter'
]
plot_coherently_averaged_1d(
    delays, avg_vis, plot_labels, low_rng,
    title=f'Figure 22: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged,\
    Psuedo-Stokes I and Q, Main-Beam Filtered Visibilities, {np.round(data.freqs[low_rng[0]] / 1e6, 1)}—{np.round(data.freqs[low_rng[-1]] / 1e6, 1)} MHz'
)

Figure 22: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged, Psuedo-Stokes I and Q, Main-Beam Filtered Visibilities, 50.0—84.2 MHz

No description has been provided for this image
In [39]:
# Coherently-average visibilities
delays, avg_vis = coherently_average_visibilities(
    [data_p_inpaint, data_p_delay_filt, data_p_xtalk_filt, data_beam_filt], 
    flags_p_inpaint, nsamples_p_inpaint, high_rng
)

plot_labels = [
    'DPSS Inpainted', 'DPSS Delay-Filtered', 'DPSS Delay + Cross Talk-Filtered', 
    f'DPSS Delay-Filtered + Main-Beam Filter'
]
plot_coherently_averaged_1d(
    delays, avg_vis, plot_labels, high_rng,
    title=f'Figure 23: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged,\
    Psuedo-Stokes I and Q, Main-Beam Filtered Visibilities, {np.round(data.freqs[high_rng[0]] / 1e6, 1)}—{np.round(data.freqs[high_rng[-1]] / 1e6, 1)} MHz'
)

Figure 23: Coherently-Averaged, Delay-Transformed, Incoherently-Averaged, Psuedo-Stokes I and Q, Main-Beam Filtered Visibilities, 111.4—230.1 MHz

No description has been provided for this image

Metadata¶

In [40]:
for repo in ['numpy', 'scipy', 'astropy', 'hera_cal', 'hera_qm', 'hera_filters', 'hera_notebook_templates', 'pyuvdata']:
    exec(f'from {repo} import __version__')
    print(f'{repo}: {__version__}')
numpy: 2.2.2
scipy: 1.15.1
astropy: 7.0.1
hera_cal: 3.7.1.dev45+g4a0c6f1
hera_qm: 2.2.1.dev2+ga535e9e
hera_filters: 0.1.6.dev9+gf165ec1
hera_notebook_templates: 0.1.dev989+gee0995d
pyuvdata: 3.1.3
In [ ]: