CaltechExperimentalGravity / CaltechExperimentalGravity/system_ident

Ramp contract: _soft_start_stop is wrong for a looping transport (2.8e-1 FRF error)

Open
#9 1 comment 0 reactions 0 assignees View on GitHub
bug
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.