Multi-epoch and Cross-GPR models#

Cross-GPR extends the frequency covariance model with covariance between observing epochs. It is useful when a component is expected to be shared, partly shared, or to decorrelate as a function of time.

Note

Multi-epoch models are not yet available through the TOML configuration-driven interface. They currently use the advanced API: construct MultiEpochData, wrap each signal kernel in TimeKron, create a MultiGPRegressor, and run a sampler directly.

Data requirements#

Multi-epoch fits use MultiEpochData. All epochs must share their frequency and UV layout. Epoch coordinates must use a consistent unit because the same coordinates are used by time-dependent covariance parameters.

Each signal component is combined with TimeKron, which forms the joint frequency-time covariance. Every time covariance has a unit diagonal, so the component variance remains entirely in its frequency kernel.

Available time covariances#

Class

Epoch covariance \(B_{ij}\)

Parameters

Behavior

CoherentTimeCovariance

\(B_{ij}=1\)

None

One realization is shared by every epoch.

IndependentTimeCovariance

\(B_{ij}=\delta_{ij}\)

None

Every epoch contains an independent realization.

SharedFractionTimeCovariance

\(B_{ij}=\rho+(1-\rho)\delta_{ij}\)

rho in \([0,1]\); default 0.5; fixed or fitted

A fraction rho of the variance is shared by every epoch. The remainder is independent and does not depend on epoch separation. rho=0 and rho=1 recover the independent and coherent limits.

ExponentialTimeCovariance

\(B_{ij}=\exp(-|t_i-t_j|/\tau)\)

tau > 0; default 1.0; fixed or fitted

Correlation decays with epoch separation. tau uses the epoch coordinate unit; short and long tau approach the independent and coherent limits.

Configuring a time-dependent component#

Wrap the frequency kernel and time covariance first, then configure their parameters through the resulting component. TimeKron routes each parameter to the part that defines it:

from ps_eor.ml_gpr.kernels import (
    ExponentialTimeCovariance,
    TimeKron,
    UVScaledKernel,
)
from ps_eor.ml_gpr.priors import Log10UniformPrior, UniformPrior

systematics = TimeKron(
    UVScaledKernel(family="exponential", lengthscale=1.0),
    ExponentialTimeCovariance(tau=1.0),
)
systematics.set_free(
    "variance", Log10UniformPrior(-5, -1), log_scale=True)
systematics.set_fixed("lengthscale", 1.0)
systematics.set_free("tau", UniformPrior(0.1, 30))

Configuration directly on systematics.freq_kern and systematics.time_cov remains available when access to the individual objects is useful.

For SharedFractionTimeCovariance, posterior products may also select the latent ":coherent" and ":independent" parts of a component.

Power spectra of the coherent and independent parts#

The suffix is appended to the component-selection pattern passed to get_ps_stack(). For a shared-fraction component named "sys", its total, coherent, and independent power spectra for one epoch are:

import matplotlib.pyplot as plt

ps_total = result.get_ps_stack(
    ps_gen,
    kbins,
    n_pick=50,
    kern_name="sys",
    epoch=0,
)
ps_coherent = result.get_ps_stack(
    ps_gen,
    kbins,
    n_pick=50,
    kern_name="sys:coherent",
    epoch=0,
)
ps_independent = result.get_ps_stack(
    ps_gen,
    kbins,
    n_pick=50,
    kern_name="sys:independent",
    epoch=0,
)

fig, ax = plt.subplots()
ps_coherent.get_ps3d().plot(ax=ax, label="Coherent")
ps_independent.get_ps3d().plot(ax=ax, label="Independent")
ax.legend()

Here result is the SamplerResult returned by the advanced sampler interface. Component globs remain valid, for example kern_name="sys*:coherent".

Set epoch to another integer to obtain that epoch. epoch="combine" is also supported, but averaging affects the two parts differently: the coherent realization is preserved, whereas independent realizations average down. get_ps_stack requires one cube per posterior draw and therefore does not accept epoch="all".

The suffixes are available only for components using SharedFractionTimeCovariance. The exponential covariance has no separate coherent and independent latent processes.

Choosing a time covariance#

Use empirical cross-covariance and injection tests to motivate the model. Coherence measured from one realization can contain chance correlations, anti-correlations, and residual systematics, so it should not be treated directly as a covariance matrix without checking positive definiteness and statistical stability.

Start with coherent and independent limits. Add a shared fraction or time-dependent decay only when the data distinguish it and when the fitted component has a defensible physical interpretation. The multi-epoch tutorials show how to construct these alternatives and compare their posterior behavior.