CaltechExperimentalGravity / CaltechExperimentalGravity/system_ident

Stage D: read cache — simultaneous mode is currently slower than sequential (7.0 h -> 2.5 h)

Open
#15 1 comment 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Python
Stars
0
Forks
1
PR merge metrics
No merged PRs in 30d

Description

**Stage D (spec §4.2).** A performance bug that defeats the entire purpose of simultaneous mode.

[`src/system_ident/loop.py:166`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/loop.py#L166) `_inject_all` stages every DoF, then `_measure_dof(...,
reuse_injection=True)` runs **once per DoF**, each calling `self.backend.read(read_chans, total_dur)`
([`src/system_ident/loop.py:214`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/loop.py#L214)) with a per-DoF channel subset. On a continuous AWG loop that is
physically valid — all DoFs are driven the whole time — but it spends `N * total_dur` of wall clock to
obtain information available in `1 * total_dur`. Simultaneous mode exists precisely to measure N DoFs in
the time of one.

Wall-clock, at physics-sized resolution (Q≈50 at 0.67 Hz → `df ≈ 3 mHz`, `T ≈ 256 s`, per
[`src/system_ident/design/resolution.py:15`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/design/resolution.py#L15)), for 3 DoF × `max_iter = 3`:

| | driven reads | quiet reads | total |
|---|---|---|---|
| today | 9 × 2048 s | 3 × 2048 s | **≈7.0 h** |
| with a read cache | 3 × 2048 s | 1 × 2048 s | **≈2.5 h** |

(At the smaller `configs/rtsfreerun_hsts.yml` timing it is ≈32 min, of which 28% is pure `start_buffer`
dead time — so `start_buffer` is *not* the cost driver at realistic resolutions; the read multiplicity is.)

### Fix

Give `CDSBackend` a **read cache** keyed on `(injection generation, requested duration)`: fetch the union
of every channel the campaign cares about (`exc_channels ∪ readback_channels ∪ drive`) once per window,
and serve per-DoF subsets while the generation is unchanged. Transparent to `SysIDLoop`, so the loop stays
backend-agnostic per [`src/system_ident/backends/base.py:3`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/backends/base.py#L3).

It also collapses the three serial quiet reads at [`src/system_ident/loop.py:144`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/loop.py#L144) into one buffer.

### Also in scope: settle once, not twice

The sibling project sleeps a settle *and* this repo drops `n_transient` periods inside the record while
scaling `_fisher_time_factor` ([`src/system_ident/loop.py:110`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/loop.py#L110)) accordingly. Doing both pays for
settling twice **and** makes the reported Fisher time wrong, since that factor assumes the dropped periods
were inside the paid-for record. Sleep only `ramp_s` plus a margin, keep `n_transient >= 1` inside the
record (it is the adaptive guard against a wrong prior Q), and do **not** add a `settle_duration` config
knob that duplicates it.

---
**Campaign:** CDS hardware backend · branch [`feat/cds-hardware-backend`](https://github.com/CaltechExperimentalGravity/system_ident/tree/feat/cds-hardware-backend)
· [spec](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/docs/superpowers/specs/2026-08-03-cds-hardware-backend-design.md) · [plan](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/docs/superpowers/plans/2026-08-03-cds-hardware-backend.md) · [handoff](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/notes/cds-hardware-bringup-2026-08.md)
*Code is deferred until the plan and issues have been reviewed.*

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with src/system_ident/loop.py at _inject_all, _measure_dof, the quiet-read path, and _fisher_time_factor, then inspect the CDSBackend implementation and the base backend interface. The work is complete when one cached union read serves the per-DoF subsets and quiet reads, while settling occurs only once and n_transient remains inside the record without a separate settle_duration setting.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
backend, performance
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.