# SR Analysis: Phase-State SINDy Results Report > Date: 2026-06-15 > Project: DynamisLab — Active hydrodynamic cloaking and illusion using DRL on a fluidic pinball. > Analysis pipeline: SINDy (STLSQ) + feature engineering for interpretable control law extraction. --- ## Executive Summary Three key findings from the SR analysis pipeline: 1. **Illusion 0.75L + 1L: New route validated.** Phase-state features + error-state + absolute action output achieves closed-loop similarity of **0.96+** (97% of PPO) with **zero action history features**. This proves that physically meaningful control laws can be extracted without relying on action memory. 2. **Illusion 1.5L: Regime shift identified.** The 1.5L target exhibits bang-bang/saturated control (alpha range [-8, 8], autocorrelation r=0.07). Linear SINDy is fundamentally inadequate (R2=0.12). This is a regime boundary, not a modelling failure. 3. **Karman: State representation still incomplete.** The same phase-state approach reaches 0.699 (vs 0.901 baseline with action history). The problem is not the output form (derivative vs absolute) but insufficient input state information for the Karman scene. --- ## 1. Methodology ### 1.1 Feature Architecture (Final) Three feature levels were tested for fitting `alpha = f(state)` or `d(alpha)/dt = g(state)`: | Level | Features | Dim | Description | |-------|----------|:---:|-------------| | Static | u_m, u_a, u_c, v_a, Cd_tot, Cd_rear, Cl_tot, Cl_diff | 8 | Current-step physics only, no memory | | Phase-state | u_a, du_a/dt, Cl_tot, dCl_tot/dt, Cd_tot, Cd_rear (+error terms) | 6+4 | Oscillation phase + rate + drag feedback | | Full-lag | Static + lag-1 of all 8 | 16 | Brute-force temporal context (baseline) | ### 1.2 Output Modes Two output targets were compared: - **Derivative mode**: predict d(alpha)/dt, then integrate `alpha(t) = alpha(t-1) + dt_c * dalpha/dt` - **Absolute mode**: predict alpha directly, no integration needed ### 1.3 Evaluation Metrics Models are evaluated on: 1. **One-step R2**: fit quality on training data 2. **Offline multi-step rollout**: 1/5/20/50 step recursive prediction on held-out PPO data 3. **CFD closed-loop**: full CFD environment with SINDy control law, DTW similarity vs target --- ## 2. Illusion Results ### 2.1 Three-Scene Summary | Scene | S | Old v23 (a_lag) | New phase+error+abs | PPO baseline | % of PPO | Features | Action history? | |------|:--:|:----------------:|:-------------------:|:------------:|:--------:|----------|:---------------:| | 0.75L | 400 | 0.908 | **0.974** | 0.972 | 100.2% | 10-dim (ILLUSION_PHASE) | **No** | | 1L | 600 | 0.962 | **0.958** | 0.973 | 98.5% | 10-dim (ILLUSION_PHASE) | **No** | | 1.5L | 800 | 0.926 | **N/A** | 0.945 | — | — | Bang-bang regime | **Key insight**: The 0.75L scene's new route **outperforms** the old v23 (0.974 vs 0.908), while 1L matches it within 1.5%. This definitively proves that "action history is not necessary." ### 2.2 Illusion 1L Front Coefficients (Phase-State, Absolute Output) ``` alpha_F = f(u_a, du_a/dt, Cl_tot, dCl_tot/dt, Cd_tot, Cd_rear, Cd_err, Cl_err, dCd_err/dt, dCl_err/dt) R2 = 0.987 ``` Key contributors (sorted by |coef|): Cd_rear > Cd_tot > Cd_err > Cl_tot > Cl_err > dCl_err/dt > dCd_err/dt The formula is dominated by **drag-based feedback** (Cd_tot, Cd_rear, Cd_err), with the oscillation phase (u_a, Cl_tot) providing secondary modulation. ### 2.3 Illusion 1.5L — Regime Shift Evidence | Metric | 1L | 1.5L | Ratio | |--------|:--:|:----:|:-----:| | Alpha range (front) | [-0.36, 1.11] | **[-8.0, 8.0]** | 10x | | 1-step autocorrelation | 0.957 | **0.065** | — | | d(alpha)/dt std | 0.12 | **6.07** | 50x | | Linear SINDy R2 | 0.987 | **0.124** | — | The 1.5L controller operates at saturation limits (maximum rotation speed), flipping between extremes. This is consistent with the frequency-doubling control strategy reported in the confirmation report. --- ## 3. Karman Results ### 3.1 Ablation Study (re100) | Configuration | Feat | Output | R2 | Closed-loop | % of PPO | |--------------|:----:|:-----:|:--:|:----------:|:--------:| | old v23 (a_lag1 dominant) | 14+3 | alpha | 0.996 | **0.901** | 94.4% | | **Phase-state -> abs (best new)** | **6** | **alpha** | **0.965** | **0.699** | 73.3% | | Phase-state -> deriv | 6 | dalpha/dt | 0.837 | 0.656 | 68.8% | | Phase-state + mu -> abs | 9 | alpha | 0.979 | 0.700 | 73.4% | | Expanded 10-dim -> abs | 10 | alpha | 0.980 | **0.580** | 60.8% | | Full-lag -> deriv | 16 | dalpha/dt | 0.939 | 0.619 | 64.9% | | Static -> deriv | 8 | dalpha/dt | 0.321 | 0.745 | 78.1% | **Key insight from ablation**: 1. **Phase-state + absolute output is the best new route** (0.699), but still well below the action-history baseline. 2. Adding extra static features (expanded 10-dim) **hurts** closed-loop despite higher R2 — classic covariate shift. 3. The static->deriv paradox: low R2 (0.321) but good closed-loop (0.745), because no-memory models are naturally robust to rollout divergence. 4. Mu modulation doesn't help at single-Re; its value will appear in cross-Re fitting. ### 3.2 Cross-Re Generalization (old v23 model) | Re | Type | Closed-loop | Note | |:--:|:----:|:----------:|------| | 50 | Training | 0.582 | Low-frequency shedding | | 100 | Training | **0.901** | Default / best | | 200 | Training | 0.793 | Moderate degradation | | 400 | Training | 0.664 | High-Re challenge | | 25 | Unseen (subcritical) | 0.567 | Below Hopf bifurcation | | 70 | Unseen | 0.577 | Between Re50 and Re100 | | 150 | Unseen | 0.595 | Between Re100 and Re200 | | 300 | Unseen | 0.541 | Outer extrapolation | ### 3.3 One-Step R2 vs Closed-Loop Paradox A key phenomenon discovered during this work: **high one-step R2 does not predict good closed-loop performance** when temporal features (lags, derivatives) are present in the input. This is because: - **Training**: features use ground-truth PPO observations - **Deployment**: features use SINDY-controlled observations (distribution shift) - Temporal features amplify this shift recursively --- ## 4. Roadmap to Next Steps ### 4.1 Illusion: Proceed to PySR The 0.75L and 1L scenes are ready for symbolic regression. Recommended input: ```python ILLUSION_PHASE_KEYS = [ "u_a", "du_a_dt", # oscillation phase "Cl_tot", "dCl_tot_dt", # lift dynamics "Cd_tot", "Cd_rear", # drag feedback "Cd_err", "Cl_err", # force error "dCd_err_dt", "dCl_err_dt", # error dynamics ] ``` Output: absolute alpha (non-dimensional action), no integration. First do separate PySR for each scene, then compare formula structure for shared backbone. ### 4.2 Karman: CCD/OID for state completion The 0.699 ceiling suggests missing state variables. Candidate directions: - Recirculation zone length / reattachment point - Wake centerline deflection - POD mode coefficients for phase completion - CCD modes correlated with control action ### 4.3 SR / CCD / OID Integration Framework ``` ┌─────────────────────────────────────┐ │ Control Objective │ │ (stealth / illusion / erase) │ └──────────┬──────────────────────────┘ │ ┌──────────▼──────────┐ │ DRL Policy │ │ (PPO + Sin act) │ └──────────┬──────────┘ │ ┌────────────────┼────────────────┐ │ │ │ ┌────────▼──────┐ ┌─────▼──────┐ ┌──────▼─────────┐ │ SINDy / SR │ │ CCD / OID │ │ Validation │ │ obs -> act │ │ obs -> z │ │ CFD closed- │ │ white-box │ │ structure │ │ loop + DTW │ │ control law │ │ analysis │ │ │ └────────┬──────┘ └─────┬──────┘ └──────┬─────────┘ │ │ │ └────────────────┼─────────────────┘ │ ┌──────────▼──────────┐ │ Interpretable │ │ Control Mechanics │ │ obs -> z -> act │ │ -> structure -> │ │ -> signature │ └─────────────────────┘ ``` --- ## 5. Code Changes Summary ### Files Modified (8 core files) | File | Changes | |------|---------| | `src/SR_analysis/utils/feature_builder.py` | PHYSICS_FEAT_KEYS, ILLUSION_ERR_KEYS, PHASE_STATE_KEYS, ILLUSION_PHASE_KEYS, KARMAN_EXPANDED_KEYS; obs dynamics (lag1 + derivative); error-state computation; 1D target_forces support | | `src/SR_analysis/utils/sindy_fitter.py` | compute_action_deriv(); get_feature_matrix_deriv() with output_mode="deriv"|"absolute"; include_mu support | | `src/SR_analysis/sindy/run_all_v2.py` | run_single_scene_deriv(); run_joint_karman_deriv(); --deriv, --phase, --karman-expand, --karman-mu, --output-mode, --augment-level CLI | | `src/SR_analysis/validate/run_closed_loop.py` | predict_v23_deriv() with output_mode; mode="abs" branch; load_sindy_coefs returns "mode" | | `src/SR_analysis/validate/run_closed_loop_illusion.py` | Support predict_v23_deriv; auto-detect SINDy mode from coefs | | `src/SR_analysis/utils/__init__.py` | Export new constants and functions | | `src/SR_analysis/sindy/wrap_joint.py` | Parameterized for karman/illusion | | `src/SR_analysis/validate/eval_rollout.py` | **New**: offline multi-step rollout evaluation | ### Key Design Principles 1. **No action history in features** for all new routes (PHASE_STATE_KEYS, ILLUSION_PHASE_KEYS) 2. **Time-normalized derivatives** for cross-scene compatibility: `dx/dt = (x(t) - x(t-1)) / dt_c` 3. **Error-state** for Illusion: Cd_err, Cl_err encode current-to-target deviation 4. **Output flexibility**: both derivative and absolute modes supported --- ## 6. Figures All figures in `docs/figures/SR_analysis/`: - **fig1_illusion_comparison.png**: Illusion 3-scene comparison bar chart - **fig2_karman_ablation.png**: Karman re100 ablation across 7 configurations - **fig3_karman_generalization.png**: Karman cross-Re generalization (training vs unseen) - **fig4_r2_vs_closedloop.png**: One-step R2 vs closed-loop paradox scatter - **fig5_illusion_coefficients.png**: Illusion 1L front feature coefficients - **fig6_roadmap.png**: Research progress roadmap