stability_metrics
Find every unity-gain and -180° phase crossover in a loop-gain AC sweep, reporting phase/gain margins at each crossing to correctly classify stability, including conditional systems.
Instructions
Find EVERY unity-gain and -180° phase crossover in a loop-gain AC sweep, report phase margin at each unity-gain crossing and gain margin at each -180° crossing. Replaces the single-crossing approximation in simulation_summary, which returns wrong margins on conditionally-stable systems.
Run this on a LOOP-GAIN signal (typically a dedicated middlebrook probe or .AC of the open loop). Running on a closed-loop output gives meaningless margins — if the DC phase starts near ±180° (a closed-loop / inverting output rather than a loop probe, which starts near 0°), a warning says so in warnings.
Returns: dc_gain_db, high_freq_gain_db, stability classification (stable / unstable / conditional / unconditional / always_below_unity), all crossings, per-crossing margins, and the worst-case values.
Nuances:
Phase is UNWRAPPED first, so systems whose phase drops past -360° are handled correctly (otherwise the raw wrap hides the crossing).
If phase NEVER crosses -180°, gain margin is 'infinite' (returned as null with stability='unconditional'). That's stable, not an error.
If gain NEVER reaches unity, phase margin is undefined (returned as null with stability='always_below_unity').
Multiple crossovers trigger stability='conditional' and a warning — each one needs its own review.
For -3 dB filter cutoffs use bode_metrics(mode='filter'); for custom crossings use bode_metrics(mode='crossing').
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| step | No | Step index for .step sweeps | |
| format | No | ||
| job_id | No | Analyze a completed job run by id instead of a raw_file path; pair with ``run_index``. Lets you read a sweep / Monte-Carlo run's margins. | |
| signal | Yes | Loop-gain signal (e.g. 'V(loop)') | |
| raw_file | No | Path to loop-gain AC analysis .raw file. Pass this OR ``job_id`` (a job run), not both. | |
| run_index | No | 0-based run to analyze when ``job_id`` is given (default 0). | |
| min_separation_decades | No | Merge near-duplicate crossovers closer than this many decades. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| signal | Yes | ||
| warnings | Yes | ||
| stability | Yes | ||
| dc_gain_db | Yes | ||
| gain_margins | Yes | ||
| phase_margins | Yes | ||
| high_freq_gain_db | Yes | ||
| gain_margin_worst_db | No | ||
| phase_180_crossovers | Yes | ||
| unity_gain_crossovers | Yes | ||
| phase_margin_worst_deg | No |