CaltechExperimentalGravity / CaltechExperimentalGravity/system_ident
Ramp contract: _soft_start_stop is wrong for a looping transport (2.8e-1 FRF error)
- Dominant language
- Python
- Stars
- 0
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
**Stage B4 (spec §2.2).** The base-class contract currently mandates a construction that is
broken on real hardware.
[`src/system_ident/backends/base.py:26`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/backends/base.py#L26) applies a Tukey envelope to the **whole injected array**, and
[`src/system_ident/backends/base.py:30`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/backends/base.py#L30) says every actuating backend MUST use it. But `awg`'s
`ArbitraryLoop` **repeats** the staged array, so the taper becomes a periodic **amplitude modulation at
the loop period**, not a one-shot envelope: the drive is then periodic at the loop period rather than at
`nperseg`, the reshape at [`src/system_ident/loop.py:411`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/loop.py#L411) is no longer synchronous, and the DFT
leaks. Worse, the seam (ramp to zero, ramp from zero) re-excites the plant's transient **every cycle**,
so no steady state is ever reached — `_choose_transient` cannot help, because the transient recurs
rather than decays.
Measured (`ramp_s = 3.0` s over a 32 s / 8-period array, looped, reading 8 periods from the steady stream):
| construction | max rel FRF error |
|---|---|
| `_soft_start_stop` + loop, read at the loop seam | **2.81e-1** |
| same, read rolled 3000 samples | 6.68e-2 |
| one-shot lead+record+tail (the `RTSfreerunBackend` construction) | 8.8e-12 |
| **AWG's own `ramptime`, array untapered** | **1.4e-11** |
This is the live configured path — `configs/*.yml` set `t_ramp: 3.0`, mapped to `ramp_s` at
[`src/system_ident/backends/rtsfreerun_adapter.py:143`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/backends/rtsfreerun_adapter.py#L143).
### Fix
Rewrite the contract at [`src/system_ident/backends/base.py:19`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/backends/base.py#L19) and
[`src/system_ident/backends/base.py:45`](https://github.com/CaltechExperimentalGravity/system_ident/blob/feat/cds-hardware-backend/src/system_ident/backends/base.py#L45) — a clarification, not a weakening:
> A backend MUST apply a `ramp_s`-second on/off envelope, **either** via `_soft_start_stop` on a one-shot
> lead+record+tail array (see `RTSfreerunBackend.read`) **or** via an equal-duration transport-level gain
> ramp (see `CDSBackend`) — **never both**, and it MUST document which.
Double-ramping squares the envelope over `2*ramp_s`, lowering the leading periods' energy further and
breaking the equal-energy assumption the previous issue relies on.
`CDSBackend` therefore overrides `_soft_start_stop` to a pass-through and uses
`inj.start(ramptime=...)` / `inj.stop(ramptime=...)`, which is what the sibling project does. It also
makes `ramp_down(channel, secs)` map exactly onto `inj.stop(ramptime=secs)`; under a one-shot
construction `ramp_down` would have to rewrite an already-queued array, which is impossible.
### Acceptance
A test asserting the staged CDS drive is an **untapered integer-period tiling** with
`ramptime == ramp_s` — that is what stops the clarification becoming a loophole.
---
**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
Read src/system_ident/backends/base.py and compare RTSfreerunBackend.read with CDSBackend, then inspect the loop handling in src/system_ident/loop.py around line 411. Verify the staged CDS drive is an untapered integer-period tiling, uses transport-level ramps for exactly ramp_s, and does not apply both ramp mechanisms.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend, embedded-iot
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100