Observation
Inspecting the simulated SWAT Set A 14-day artifact (produced by psim v0.1.2 from `PARAM_SET_A` + `INIT_STATE_A`), the latent Zt trace stays mostly in [0, 3] over the full trajectory. The deep-sleep threshold is c2 = c_tilde + delta_c = 3.0 + 1.5 = 4.5. So sleep_level=2 almost never fires.
In the ordinal sleep generator (`gen_sleep` in `version_1/models/swat/simulation.py`):
```
P(level=2 = deep) = sigmoid(Zt - c2)
```
With Zt peaking at ~3 (and rarely at ~3.5), P(deep) ≈ sigmoid(-1.5) ≈ 0.18 at peaks, P(deep) ≈ sigmoid(-3) ≈ 0.05 typically. The simulated label sequence shows < 5% deep-sleep coverage, vs the ~20-25% deep sleep typical for healthy adults.
See attached: psim diagnostic plot (`outputs/swat/set_A_healthy_14d/swat_channels.png` produced by `psim/examples/swat/14d_set_A_healthy.py`).
Why Zt amplitude is low
The flip-flop dynamics:
```
dZt = (A_SCALE * sigmoid(u_Z) - Zt) / tau_Z # A_SCALE = 6.0
u_Z = -gamma_3 * W - V_n + beta_Z * a
```
For overnight sleep (W=0) with Set A defaults (Vn=0.3, beta_Z=2.5, tau_a=3h):
- Adenosine `a` rises during wake (W=1), with timescale tau_a=3h. After ~16h wake, a≈1.
- At sleep onset: u_Z = -0.3 + 2.5·1 = 2.2 → Zt → 6 · sigmoid(2.2) ≈ 5.4 (deep)
- But `a` clears with same timescale 3h during sleep, so Zt's peak drops over the night.
In practice, the Zt peak in the artifact is only ~3, suggesting either:
- `a` doesn't reach high values during wake (peak in plot looks like 0.7-0.8, not 1.0)
- OR `tau_Z=2h` slow-tracks a fast-changing target
- OR coupling `beta_Z=2.5` is on the low side relative to what's needed
Suggested re-tuning (any one or combination)
For the healthy basin (Set A) to produce realistic deep-sleep proportions (~20-25%):
- Lower c_tilde (e.g. 2.5 → c2 = 4.0 makes deep-sleep threshold reachable for typical Zt~3-4)
- Boost beta_Z (e.g. 2.5 → 4.0) to amplify a→Zt coupling, pushing Zt closer to 5-6 in deep sleep
- Lower tau_Z (2h → 1h) so Zt tracks a more aggressively
- Keep tau_a=3h but lower its decay during sleep — would require a model change
Empirically, (1)+(2) combined would make the deep-sleep threshold reachable without changing the timescales.
Why this matters
For SMC² inference, the sleep ordinal channel is essentially providing only binary information (wake vs any sleep) when level=2 almost never fires. This impairs identification of:
- `c_tilde` (the level-1 threshold)
- `delta_c` (the level-2 threshold offset; effectively unconstrained because no level-2 data)
- `beta_Z`, `tau_a` (which together set Zt's overnight amplitude)
All three currently come back with narrow CIs locked off-truth in the SMC² rolling-window estimation (separate finding from the SMC² bug currently being investigated as part of the SWAT port to smc2-blackjax-rolling).
Out of scope here
- Fix for the SMC² inference bug (in `smc2-blackjax-rolling/smc2bj/log_density/gk_dpf_v3_lite.py`). That's tracked separately in the SMC² repo (private).
- Sets B/C/D may need similar audit but Set A is the immediate concern.
Reference
- Plot: `~/Repos/Python-Model-Scenario-Simulation/outputs/swat/set_A_healthy_14d/swat_channels.png`
- Generator: `version_1/models/swat/simulation.py:gen_sleep`
- Healthy-adult deep-sleep reference: 13-23% of total sleep, declining with age (Ohayon et al. 2004).
Observation
Inspecting the simulated SWAT Set A 14-day artifact (produced by psim v0.1.2 from `PARAM_SET_A` + `INIT_STATE_A`), the latent Zt trace stays mostly in [0, 3] over the full trajectory. The deep-sleep threshold is c2 = c_tilde + delta_c = 3.0 + 1.5 = 4.5. So sleep_level=2 almost never fires.
In the ordinal sleep generator (`gen_sleep` in `version_1/models/swat/simulation.py`):
```
P(level=2 = deep) = sigmoid(Zt - c2)
```
With Zt peaking at ~3 (and rarely at ~3.5), P(deep) ≈ sigmoid(-1.5) ≈ 0.18 at peaks, P(deep) ≈ sigmoid(-3) ≈ 0.05 typically. The simulated label sequence shows < 5% deep-sleep coverage, vs the ~20-25% deep sleep typical for healthy adults.
See attached: psim diagnostic plot (`outputs/swat/set_A_healthy_14d/swat_channels.png` produced by `psim/examples/swat/14d_set_A_healthy.py`).
Why Zt amplitude is low
The flip-flop dynamics:
```
dZt = (A_SCALE * sigmoid(u_Z) - Zt) / tau_Z # A_SCALE = 6.0
u_Z = -gamma_3 * W - V_n + beta_Z * a
```
For overnight sleep (W=0) with Set A defaults (Vn=0.3, beta_Z=2.5, tau_a=3h):
In practice, the Zt peak in the artifact is only ~3, suggesting either:
Suggested re-tuning (any one or combination)
For the healthy basin (Set A) to produce realistic deep-sleep proportions (~20-25%):
Empirically, (1)+(2) combined would make the deep-sleep threshold reachable without changing the timescales.
Why this matters
For SMC² inference, the sleep ordinal channel is essentially providing only binary information (wake vs any sleep) when level=2 almost never fires. This impairs identification of:
All three currently come back with narrow CIs locked off-truth in the SMC² rolling-window estimation (separate finding from the SMC² bug currently being investigated as part of the SWAT port to smc2-blackjax-rolling).
Out of scope here
Reference