SynDiff · F1 = S24 cam 2 CCD 2, one frame · 2026-10-01 · run dir /astro/armin/koji/syndiff/dev_runs/localbg_20260930/

The Star-Lifted Background

How the background estimate put a bump of each star's own light under that star, why that left a hole around every faint star in the difference image, and why the ePSF fit then needed a fitted background term to look right.

Short version
  1. Each bright star is masked with a circle before the background is fitted. The circle is too small: the star's wing is still well above zero at its edge.
  2. The background inside the circle is filled in from the pixels around it. Those pixels still carry the star's wing, so the fill puts a bump of the star's own light under the star: +0.41 e⁻/s for T 8–10, +0.11 e⁻/s for T 12–13 (stacked medians). The production biharmonic fill makes it worse: it carries the wing's rising slope inward and overshoots.
  3. That bump is subtracted as "sky", so in the difference image hp_d every star sits in a shallow hole. For faint stars the hole is a large fraction of the outer wing.
  4. An ePSF fit without a background term cannot model a hole. It leaves a negative ring, the held-out faint-star wings are biased low, and the median local sky offset around T 10–13 stars is −0.12 e⁻/s. A fitted flat background soaked this up, which is why it looked necessary.
  5. Fix: harmonic fill plus 2 extra pixels of mask around each star (tessreduce_star_mask_pad_px: 2). With the background rebuilt this way, an ePSF fit with no background term matches the fit that had one.

Where it sitsThe background chain

The background is estimated once per frame, from a first-pass difference image, and then subtracted from the science image before the final Hotpants subtraction.

$$D_{\rm raw}(\mathbf{x}) = I(\mathbf{x}) - (K \ast T)(\mathbf{x}), \qquad b = \mathcal{F}\big[D_{\rm raw}\ \text{on fit pixels}\big], \qquad D = I - b - (K' \ast T)$$

$I$: the science FFI (e⁻/s). $T$: the PS1-based template on the TESS grid, with every star brighter than Tmag 13 removed (bright_maglim), so those stars are fully present in $D_{\rm raw}$.

$K$, $K'$: the PSF-matching kernels of the first pass and of the final Hotpants run.

$D_{\rm raw}$: the estimator input, stored as ks_d + ks_b.

Fit pixels: shared-mask value 0 or 32. Bit 2 marks a circle around each star of radius 9 / 8 / 7 / 6 px for Tmag 8–10 / 10–11 / 11–12 / 12–13; these pixels are excluded.

$\mathcal{F}$: smooth background fit on the fit pixels, then filling of the excluded pixels: biharmonic in production, harmonic (Laplace) since 70cba3c.

$b$: the background map ks_b (e⁻/s). $D$: the difference image hp_d that the ePSF is fitted on.

If $b$ were pure sky, a star would sit on zero in $D$. Anything of the star's own light that ends up in $b$ is subtracted from the star.

Step 1The mask circle ends while the star is still bright

Stack the estimator input around isolated stars (no other catalogue star within 16 px), and look at the ring of fit pixels just outside the circle. That ring is what the background fill uses as its boundary value.

Azimuthal profiles per magnitude bin: star light in the estimator input crossing the mask edge, with production, harmonic and fixed background levels
Azimuthal median profiles, stacked over isolated stars, levels relative to an r = 13–15 px annulus. Black: star light in the estimator input. Grey band: the masked circle. Orange band: the first 2 px of fit pixels (the rim). Coloured: the background $b$ the estimator produced: production, harmonic only, harmonic + pad 2. At the rim the black curve is still clearly positive for T 8–11. Production stays above the rim level all the way in. Harmonic roughly averages the rim. Pad 2 starts the boundary 2 px further out, where the wing is near zero, and the bump almost disappears.

The circle radii were chosen for core masking, not for the wing. TESS's PSF is broad, so at the edge of a 9 px circle a T 9 star still contributes a few tenths of an e⁻/s per pixel. That is comparable to the per-pixel noise in a single 30-min FFI.

Step 2The fill turns that rim light into a bump under the star

The same thing shown as images. The left column is exactly what the background fit sees: the fit pixels only, with the circle blank. The other columns are the filled background in three versions, on one colour scale.

Median stacks of the estimator input on fit pixels, and of the background in production, harmonic and harmonic-plus-pad-2 versions, per magnitude bin
Median stacks, 31 × 31 px around isolated stars; n per bin on the left. Column 1: estimator input on fit pixels (±1 e⁻/s). The red ring hugging the circle is the star's wing. Columns 2–4: background $b$ (±0.4 e⁻/s), dashed = mask circle, dotted = circle + 2 px. The number is the stack value at the star pixel. Production builds a bump of +0.41 / +0.23 / +0.20 / +0.11 e⁻/s; harmonic only +0.15 / +0.10 / +0.04 / +0.03; harmonic + pad 2 +0.03 / +0.03 / −0.00 / −0.02.

In an actual frame, single stars are noisier than the stack: the background map varies by several tenths of an e⁻/s on 10–20 px scales. The bumps are still visible, one per star, when the fixed background is subtracted from the production one.

A 120 by 120 pixel region of F1: estimator input, production background, fixed background, and their difference with a bump at most stars
A real 120 × 120 px region of F1 (x 1720–1840, y 840–960). Picked by rule, not by eye: the box with the most isolated T 8–11 stars among boxes holding at most 30 stars with T < 13. Dashed circles are the bit-2 mask circles. Panel 4 is production − fix: the median at the 29 star positions is +0.11 e⁻/s, against +0.002 e⁻/s at pixels more than 16 px from any star. Some blue patches also appear; those are the separate biharmonic gap-fill artefact (positive and negative patches) that the harmonic fill already removed.

Step 3Subtracting the bump leaves a hole in hp_d

Hotpants is run on $I - b$, so the bump is removed from the star itself. In $D$ = hp_d each star now sits in a shallow depression the size of its mask circle. I rebuilt the F1 frame with the production code twice: once with production settings (bit-identical to the stored ks_b and hp_d), and once with the fix. Their difference is exactly what the bump took away.

Top: hp_d with fix minus production hp_d, stacked, positive inside the mask circle. Bottom: residual profiles relative to a fixed model for production, harmonic and fix
Top: stacked hp_d(fix) − hp_d(production), core r < 3 px greyed: the two Hotpants runs fit slightly different kernels, which changes star cores by a few e⁻/s. The fix puts back +0.16 / +0.06 / +0.07 / +0.04 e⁻/s inside the circle. Bottom: azimuthal profile of ($D$ − local sky − model) / star flux, in units of 1e-4 of the flux per pixel, with one fixed ePSF model, trained on production hp_d. Only the image changes. For T 12–13 stars, production sits up to −0.6 to −1.0 × 1e-4 below that model at 3–6 px, harmonic −0.1 to −0.35, the fix about 0 to +0.2. The model itself is biased toward the production hole, so the zero line is not the truth; the next step refits it.

Why it matters most for faint stars: the bump does not shrink in proportion to the star. In production it is still +0.11 e⁻/s for T 12–13, but a T 12.5 star (median flux about 1500 e⁻/s) has only 0.04–0.08 e⁻/s per pixel of its own wing at 6–8 px. So the hole is comparable to the whole faint-star outer wing, and a small fraction of a bright star's.

Step 4What the ePSF fit did with the hole

The forward ePSF fit models each star as flux × ePSF. A hole around every star is something it cannot represent: one shared ePSF cannot be "too faint in the wing" for faint stars only. So in a fit with no background term:

Adding a fitted flat background per star ("bg0") absorbs the hole, which is why that term looked necessary. The test is to remove the cause instead: rebuild the background, refit with no background term, and see whether the result matches production + fitted background. All fits are 5-fold, scored on held-out stars only.

Held-out residual stacks for five fits and their differences from production without a background term; bar chart of outer-wing residual
Held-out (K = 5) residual / flux stacks, 1e-4 per px. Columns 1–5 are the stacks themselves; columns 6–9 are each arm minus production-without-background. The target is column 6 (production + fitted flat background): an orange halo lifting the faint-star outer ring. Harmonic alone gets about half of it; harmonic + pad 2 matches it; pad 4 overshoots. The bottom bars are the held-out outer-wing residual (r 3–7 px); production without a background term is −9 ± 7 at T 12.5–13 (off scale).
ePSF fitlocal sky after fit,
T 10–13 (e⁻/s)
ring 3–4 change,
T 10–11 / 11–12 / 12–12.5 / 12.5–13
XP flux rms
(mmag)
axis − far
(‰)
production, no bg term−0.122—14.2−1.67
production + fitted flat bg (target)−0.010+0.09 / +0.25 / +0.52 / +0.8414.4−1.28
harmonic only, no bg term−0.085+0.05 / +0.17 / +0.43 / +0.4212.7−0.45
harmonic + pad 2, no bg term−0.018+0.08 / +0.31 / +0.77 / +0.8813.1+0.18
harmonic + pad 4, no bg term0.000+0.10 / +0.38 / +0.89 / +1.0013.3+0.26

Local sky after fit: median residual in an annulus around each fitted star, over all-star-fit stars with Tmag 10–13.

Ring 3–4 change: held-out residual / flux in the r = 3–4 px ring minus the same for production without background, ×1e-4 per px; the target row is what a fitted background does.

XP flux rms: scatter of ePSF fluxes against Gaia XP synthetic photometry.

Axis − far: flux offset between stars near and far from the optical axis.

Unchanged in every arm: the brighter-fatter core width, the XP colour term, and the held-out learning curves. The faint-star ePSF memorisation is not a background effect.

Side noteWhy the bump sat slightly off-centre

The production background bump is centred 0.15–0.9 px toward −x rather than on the star. The star stacks are centred to better than 0.15 px, so this is not a coordinate mix-up. The cause is the PSF: on this CCD the wing is lopsided toward −x and +y, roughly toward the optical axis at about (−58, 2100) px. The rim on that side holds more light, and the fill follows it.

Star light along plus and minus x and y, showing the minus-x wing several times brighter; production background stack with bump centroids toward minus x
Left, middle: stacked estimator input along 5-px-wide cuts in ±x and ±y (symlog scale; dashed = mask radius). The −x wing is several times the +x wing out to the mask edge, and +y exceeds −y. Right: T 11–12 production background stack, with the bump centroid of each magnitude bin (inside the mask circle, positive part, error = median-based standard error over stars): all four bins are shifted to −x, by 0.15–0.94 px.

FixWhat changed, and what it does not cover

Branch bkg-star-pad, commit 2ecf558 (local, not merged, not pushed). It adds tessreduce_star_mask_pad_px to background_estimate and kernel_fit; the default 0 changes nothing. With value 2, every bit-1/bit-2 star mask is grown by a 2 px disk before the background fit, so the fill's boundary sits where the wing has dropped to about zero. Combined with the harmonic fill (already the default since 70cba3c), this is the recommended setting.

The trade-off is that the background is fitted on fewer pixels: the fit fraction goes from 0.47 to 0.35. Between stars the background swings by about ±0.13 e⁻/s, and the empty-sky noise of hp_d is unchanged (0.51–0.53 e⁻/s). Pad 8 would remove the T 8–10 bump completely, but swings the background by ±0.5 e⁻/s, so it was rejected.

FilesWhere everything is

/astro/armin/koji/syndiff/dev_runs/localbg_20260930/README.md
/astro/armin/koji/syndiff/dev_runs/localbg_20260930/explainer/ (this page, figures, make_explainer_figs.py)
/astro/armin/koji/syndiff/dev_runs/localbg_20260930/rebuild/ (rebuilt frames, refits, analysis)
/home/kshukawa/syndiff_pipeline/.claude/worktrees/bkg-star-pad (code)