Gain Calibration Strategy

Objective. During bandpass calibration we derive voltage gains $g_x$ and $g_y$ that are stored in the bandpass table. The corresponding correlation-space gains are $$G_x^m = g_x \, g_x^* = |g_x|^2, \qquad G_y^m = g_y \, g_y^* = |g_y|^2.$$ After applying these gains, the corrected parallel-hand correlations of the unpolarised source 1934−638 should satisfy $$Q = XX^{ic} - YY^{ic} = 0.$$ If $Q \neq 0$, the initial gain derivation contains errors. We model and quantify these using 1934−638 measurements, and use them to update $g_x$, $g_y$ in the bandpass table. Note: $G$ operates on correlations; $g$ operates on voltages.

1. Initial Measurement Stage

The measured parallel-hand correlations are related to the true (ideal, superscript $\circ$) values by the correlation-space measurement gains $G_x^m$ and $G_y^m$:

$$XX^m = G_x^m \, XX^\circ \tag{I}$$ $$YY^m = G_y^m \, YY^\circ \tag{II}$$

where $G_x^m = g_x g_x^* = |g_x|^2$ and $G_y^m = g_y g_y^* = |g_y|^2$ ($g$ acts on voltages; $G$ acts on correlations).


2. Interim Calibration Stage

We attempt to correct the measured data by dividing out the measurement gain, producing the interim-calibrated visibility $XX^{ic}$:

$$XX^{ic} = \frac{1}{G_x^m} \cdot XX^m = G_x^{ic} \cdot XX^\circ \tag{III}$$ $$YY^{ic} = \frac{1}{G_y^m} \cdot YY^m = G_y^{ic} \cdot YY^\circ$$

The residual $G_x^{ic}$ captures how imperfect the correction was. If the correction were perfect, $G_x^{ic} = 1$ and $XX^{ic} = XX^\circ$ exactly. The goal is to measure and remove $G_x^{ic}$ and $G_y^{ic}$.


3. Analysis of Source 1934−638

1934−638 is unpolarised, so $Q^\circ = XX^\circ - YY^\circ = 0$ and each polarisation carries half the total intensity: $XX^\circ = YY^\circ = \tfrac{1}{2}I^\circ$. Substituting into (III):

$$XX^{ic} = G_x^{ic} \cdot \tfrac{1}{2}I^\circ \tag{IV}$$ $$YY^{ic} = G_y^{ic} \cdot \tfrac{1}{2}I^\circ \tag{V}$$

Adding and subtracting:

$$I^{ic} = XX^{ic} + YY^{ic} = \tfrac{1}{2}\bigl(G_x^{ic} + G_y^{ic}\bigr)\,I^\circ$$ $$Q^{ic} = XX^{ic} - YY^{ic} = \tfrac{1}{2}\bigl(G_x^{ic} - G_y^{ic}\bigr)\,I^\circ$$

4. Solving for $G_x^{ic}$ and $G_y^{ic}$

The two equations at the end of §3 have two unknowns. Adding and subtracting them directly:

$$G_x^{ic} = \frac{I^{ic} + Q^{ic}}{I^\circ} \tag{VI}$$ $$G_y^{ic} = \frac{I^{ic} - Q^{ic}}{I^\circ} \tag{VII}$$

This is the exact, assumption-free result. Both gains are fully determined by three measurables: $I^{ic}$, $Q^{ic}$ (from 1934−638 after interim calibration), and $I^\circ$ (the known true flux of 1934−638). Defining $dQ = Q^{ic}/I^{ic}$, these can be written:

$$G_x^{ic} = \frac{I^{ic}}{I^\circ}\,(1 + dQ), \qquad G_y^{ic} = \frac{I^{ic}}{I^\circ}\,(1 - dQ) \tag{VIII}$$

The prefactor $I^{ic}/I^\circ$ is the flux-scale accuracy of the interim calibration. If total-intensity has been correctly calibrated so that $I^{ic} = I^\circ$, this prefactor is unity and (VIII) simplifies to:

$$G_x^{ic} = 1 + dQ, \qquad G_y^{ic} = 1 - dQ \qquad \text{(when } I^{ic}/I^\circ = 1\text{)} \tag{IX}$$

In this case $dQ$ alone determines both gain errors. If $I^{ic}/I^\circ \neq 1$, using (IX) would absorb a flux-scale error into the bandpass table; the full form (VIII) must be used instead, requiring an independent measurement of $I^\circ$ (e.g. a flux model of 1934−638).


5. Final Calibration Table

From (III), any raw measurement $XX_{\rm target}^m$ is related to the true sky by both $G_x^m$ and $G_x^{ic}$:

$$XX_{\rm target}^m = G_x^m \cdot G_x^{ic} \cdot XX^\circ$$

We already hold $g_x^m$ (the voltage gain) in the bandpass table, and we have now derived the correction factor $G_x^{ic}$ from the 1934−638 data above. The combined voltage gain that removes both factors is:

$$g_x^f = g_x^m \cdot \sqrt{G_x^{ic}} = g_x^m \cdot \sqrt{\frac{I^{ic}}{I^\circ}\,(1+dQ)} \tag{X}$$ $$g_y^f = g_y^m \cdot \sqrt{G_y^{ic}} = g_y^m \cdot \sqrt{\frac{I^{ic}}{I^\circ}\,(1-dQ)}$$

When $I^{ic}/I^\circ = 1$, these simplify to $g_x^f = g_x^m\sqrt{1+dQ}$, $g_y^f = g_y^m\sqrt{1-dQ}$. The $\sqrt{\cdot}$ converts $G_x^{ic}$ from the correlation (power) domain in which it was derived back to the voltage domain in which bandpass tables operate. Applying $g^f$ to any new target data gives:

$$\frac{XX_{\rm target}^m}{|g_x^f|^2} = \frac{G_x^m \cdot G_x^{ic} \cdot XX^\circ}{G_x^m \cdot G_x^{ic}} = XX^\circ$$

The updated table $g^f$ replaces the interim bandpass table and is applied directly to uncalibrated data — no intermediate calibration step is required.


6. Accessing the correction factors

The pipeline produces two files alongside the per-field line plots in <data-root>/phase3/plots/:

6.1 Column schema

ColumnTypeDescription
footprintstrASKAP beam footprint name (e.g. closepack36); read from weights.footprint_name in the schedblock metadata. All rows produced from a single manifest share the same footprint; rows from different footprints (different manifests) can be safely appended before filtering.
fieldstrReference field name, e.g. REF_1324-28
variantstrbpcal (bandpass-cal measurement) or lcal (leakage-cal measurement)
beamintASKAP beam index, 0-based (0–35 for closepack36)
mean_dQfloat, %Mean signed $dQ/I$ leakage averaged across all SB_REF × ODC observations
std_dQfloat, %Standard deviation of $dQ/I$ across observations — indicates repeatability
mean_dUfloat, %Mean signed $dU/I$ (present when --dU was passed to plot_dQ_vs_beam.py)
std_dUfloat, %Standard deviation of $dU/I$
n_obsintNumber of (SB_REF, ODC) rows averaged for this beam

6.2 Reading the table

The CSV is a pure data file (column header row + data rows only) and opens cleanly in any spreadsheet. Full provenance and schema documentation is in the companion dq_du_correction_factors_README.txt in the same directory.

import pandas as pd

df = pd.read_csv("phase3/plots/dq_du_correction_factors.csv")

# Per-beam lookup for a specific footprint / field / variant / beam
row = df[
    (df.footprint == "closepack36") &
    (df.field     == "REF_1324-28") &
    (df.variant   == "bpcal") &
    (df.beam      == 12)
].iloc[0]
dq, dq_std = row.mean_dQ, row.std_dQ   # fractional Stokes-Q leakage, %
du, du_std = row.mean_dU, row.std_dU   # fractional Stokes-U leakage, %

# All 36 beams as a numpy array (for vectorised correction)
sub = df[
    (df.footprint == "closepack36") &
    (df.field     == "REF_1324-28") &
    (df.variant   == "bpcal")
].sort_values("beam")
dq_array = sub.mean_dQ.to_numpy()   # shape (36,)

6.3 Applying the correction

From equation (X), the corrected bandpass voltage gain for beam $b$ is:

$$g_x^f[b] = g_x^m[b]\,\sqrt{1 + dQ[b]/100}$$ $$g_y^f[b] = g_y^m[b]\,\sqrt{1 - dQ[b]/100}$$

where $dQ[b]$ is mean_dQ for that beam (in percent, so the division by 100 converts to a fractional correction). The $\sqrt{\cdot}$ converts from the correlation (power) domain back to the voltage domain required by the bandpass table.

The std_dQ and n_obs columns allow a downstream script to propagate uncertainty or to apply a beam-quality threshold (e.g. reject beams with $\sigma_{dQ} \gt 1\%$ or $n_{\mathrm{obs}} \lt 3$) before applying the correction.