Population inference across core workflows v0.1
FiberPhotometry now exposes the same animal-level population boundary for three additional method families: spontaneous transients, state-conditioned band power, and multi-signal association or coherence. Each adapter materializes inspectable animal-level cells before any population contrast is calculated.
One interface, domain-specific denominators
| Workflow | Within-session evidence | Animal-cell rule | Retained denominator |
|---|---|---|---|
| Spontaneous transient rate | event count and analyzed exposure | pool counts and exposure across sessions | contributing sessions, event count, exposure |
| Transient amplitude, width, or AUC | event-level kinetic summaries | summarize sessions, then aggregate sessions equally | sessions and event count |
| State-conditioned band power | complete gap-bounded Welch windows | integrate the declared band, then average sessions equally | sessions and total Welch windows |
| Lagged association or coherence | valid pairs or complete cross-spectral windows | aggregate the declared scalar across sessions | sessions and actual pair/window support |
These rules are intentionally not interchangeable. The shared population layer receives their outputs only after each animal-condition cell has been formed.
Materialize, inspect, infer
Every materializer returns a typed object with:
- domain-specific
animal_estimates; - common
population_estimatescontaining animal, level, value, source sessions, session support, and lower-level observation count; .contrast(PopulationContrastSpec(...)); and.interaction(group_assignments, PopulationInteractionSpec(...)).
For spontaneous transient rates:
from fiberphotometry import (
PopulationContrastSpec,
materialize_transient_population,
)
cells = materialize_transient_population(
quantified_sessions,
metric="rate_per_minute",
channel="NAc",
levels=("pre", "post"),
)
paired = cells.contrast(
PopulationContrastSpec(
numerator="post",
denominator="pre",
design="paired",
draws=2_000,
seed=2026,
)
)
A zero-event animal-session remains valid rate evidence when analyzed exposure is
positive. Its event observation_count is zero rather than being dropped or
invented; source_units and support still show the contributing session.
Group-by-condition interactions
The same materialized cells can test whether a repeated condition difference changes between two independent animal groups:
from fiberphotometry import (
PopulationGroupAssignment,
PopulationInteractionSpec,
)
groups = (
PopulationGroupAssignment("mouse-01", "control"),
PopulationGroupAssignment("mouse-02", "control"),
PopulationGroupAssignment("mouse-11", "treatment"),
PopulationGroupAssignment("mouse-12", "treatment"),
)
interaction = cells.interaction(
groups,
PopulationInteractionSpec(
group_numerator="treatment",
group_denominator="control",
condition_numerator="post",
condition_denominator="pre",
draws=2_000,
seed=2026,
),
)
This works identically after materialize_state_band_power_population() and
materialize_association_population(). For association, first create session
estimates with session_estimate_from_lagged() or
session_estimate_from_coherence().
Spectral example
cells = materialize_state_band_power_population(
state_psd_sessions,
states=("rest", "exploration"),
frequency_band_hz=(0.5, 2.0),
)
state_contrast = cells.contrast(
PopulationContrastSpec(
numerator="exploration",
denominator="rest",
design="paired",
)
)
Band edges are interpolated before integration by the spectral workflow. Welch windows support each session estimate but never become population replicates.
Association and coherence example
cells = materialize_association_population(
session_estimates,
metric="mean_coherence_0.5_2Hz",
pair_id="dms-green__nacc-red",
levels=("rest", "exploration"),
session_aggregation="mean",
)
The materialized observation count is the actual number of valid lag pairs or complete spectral windows carried by the session estimates. It documents support; it does not determine population weight.
Current boundary
The common v0.1 population contract is additive: it reports numerator minus denominator and the two-group difference in those within-animal differences. Specialist transient and state-band APIs still provide ratio effects and randomization p-values. They are not silently translated into the additive contract.
The adapters do not choose a transient detector, frequency band, state definition, lag, channel pair, or session aggregation policy. Those remain declared scientific choices. Richer count models, continuous moderators, partial pooling, and multi-factor models remain explicit gaps.
The governing rationale is recorded in SDR-0057.
For complete PSD, autocorrelation, lag-association, or coherence outcomes, use the vector population-curve workflow. It retains the full frequency or lag axis and lower-level support at every point rather than requiring a scalar band or lag summary.