Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 26 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,35 @@ Project Chrono for multi-body dynamics.
- **Default geometry**: `geometry/vgm45.obj` (flap), `geometry/stl_files/center_beam_w_foundation_BEM.STL` (base)
- **Default hydro data**: `hydroData/vgoswec_45.h5`
- **Wave default**: Regular waves, H = 0.05 m, T = 1.5 s
- **Four pluggable PTO controllers**: passive, optimal-passive, complex-conjugate, excitation-FF+PID
- **Four pluggable PTO controllers**: passive (placeholder — tune with tank data), optimal-passive, complex-conjugate, excitation-FF+PID

## Controller / flap-config co-design
## Controller / flap-config co-design — three-regime relay

Across the full VGOSWEC flap-vent sweep (VGM-0 = vents closed → VGM-90 = vents fully
open), the two active controllers occupy complementary period bands: **complex-conjugate
(CC) control dominates short wave periods**, while **excitation-FF+PID dominates long
periods**. The flap configuration acts as a design knob that shifts the CC→ff+PID
crossover, so the optimal controller is *configuration-dependent*.

![CC vs ff+PID capture power across VGOSWEC flap variants](analysis/comparison/figures/cc_vs_ffpid_summary.png)

*Capture power for complex-conjugate (solid) vs excitation-FF+PID (dashed) control across
all flap variants on a shared wave-period axis. CC peaks at short T; ff+PID peaks at long
T; the flap vent configuration tunes where each controller's peak — and the crossover
between them — lands. See [`analysis/comparison/`](analysis/comparison/) for the
per-variant comparison figures.*
open), three controllers occupy complementary period bands in a clean relay:

- **CC (complex-conjugate)** dominates short periods (T ≲ 2 s), tracking the Budal
theoretical optimum with up to 2.34 W at T = 1.5 s.
- **opt_passive** (optimal resistive damping) matches a tuned feedforward controller at
each flap's resonance peak with a single tuning-free coefficient. The resonance hump
marches across T = 2.5–4.75 s as the flap angle changes.
- **ff+PID** (excitation-feedforward + PID) carries the long-period tail past resonance
with no reactive-power penalty.

The flap angle acts as a co-design knob that shifts the resonance period — and thus the
crossover between regimes — across the full T = 2.5–5 s band.

![Three-regime operating envelope](analysis/three_regime/figures/operating_envelope.png)

*Master operating envelope: upper hull of captured power over all (controller, flap-angle)
combinations at every wave period. CC + VGM-0 dominates short T; opt_passive and ff+PID
with the T₀-matched flap dominate resonance; ff+PID + VGM-0 dominates the long tail.
See [`analysis/FINDINGS_3REGIME.md`](analysis/FINDINGS_3REGIME.md) for the full findings.*

Reproduce all figures from committed CSVs (no solver needed):
```bash
python3 scripts/three_regime_comparison.py --plot-only
```

## Repository structure

Expand Down
26 changes: 17 additions & 9 deletions analysis/FINDINGS.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
# Capture-Efficiency Study — Key Findings

**See [`analysis/FINDINGS_3REGIME.md`](FINDINGS_3REGIME.md) for the consolidated
three-regime relay findings (CC → opt_passive → ff+PID).**

Controller comparison across VGOSWEC flap variants (VGM-0/10/20/45/90) over a shared
wave-period grid **T = 0.5–7.0 s** (0.25 s steps, H = 0.05 m). Two controllers:
wave-period grid **T = 0.5–7.0 s** (0.25 s steps, H = 0.05 m). Three controllers:

- **CC** — complex-conjugate (reactive) control.
- **opt_passive** — optimal resistive damping at resonance, `B_opt = |Z_intrinsic(ω₀)|`.
- **ff+PID** — tuned excitation-feedforward + PID (`exc_ff_pid`), designed for T = 2–7 s.

All results are reproducible from the committed CSVs under `analysis/{cc,passive_guarded}/`
via each script's `--plot-only` mode. No solver runs are required to regenerate the figures.
All results are reproducible from the committed CSVs under
`analysis/{cc,opt_passive,passive_guarded}/` via each script's `--plot-only` mode.
No solver runs are required to regenerate the figures.

Naming convention: `P_injected_W` (reactive power returned to the fluid),
`P_converted_W` (gross PTO conversion), and captured power
Expand Down Expand Up @@ -111,16 +116,19 @@ modes.
## Reproducing the figures

```bash
# Three-regime (CC / opt_passive / ff+PID) per-flap + cross-flap + operating envelope:
python3 scripts/three_regime_comparison.py --plot-only

# Individual controller sweeps:
python3 scripts/capture_efficiency_sweep.py --plot-only # analysis/passive_guarded/figures/
python3 scripts/cc_capture_efficiency_sweep.py --plot-only # analysis/cc/figures/
python3 scripts/cc_vs_ffpid_comparison.py --plot-only # analysis/comparison/figures/
python3 scripts/passive_vs_optpassive_sweep.py --plot-only # analysis/passive*/figures/
```

## Deferred / next phase

- **Passive vs optimal-damped** comparison: configs and sweep script created; awaiting
simulation runs to populate CSVs. See `analysis/FINDINGS_PASSIVE.md` for method and
expected results.
- Optional refactor: unify the three per-script power/efficiency ceiling helpers into one
shared module so "matched ceilings" cannot drift.
- Literature cross-check (Issue #50): verify CC/opt_passive results against Falnes/Ringwood
textbook; confirm variable-geometry OSWEC operating-map novelty; check excitation-FF
velocity-tracking prior art.
- Optional refactor: unify per-script power/efficiency ceiling helpers into one shared
module so matched ceilings cannot drift.
153 changes: 153 additions & 0 deletions analysis/FINDINGS_3REGIME.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Three-Regime Relay — Key Findings

Controller co-design study across VGOSWEC flap variants (VGM-0/10/20/45/90) over
**T = 0.5–7.0 s** (0.25 s steps, H = 0.05 m). Three controllers:

- **CC** — complex-conjugate (reactive) control.
- **opt_passive** — optimal resistive damping, `B_opt = |Z_intrinsic(ω₀)|`.
- **ff+PID** — tuned excitation-feedforward + PID (`exc_ff_pid`), the `passive_guarded` arm.

All results are reproducible from committed CSVs under
`analysis/{cc,opt_passive,passive_guarded}/` via `--plot-only`. No solver runs required.

---

## 1. Three-regime relay (headline result)

The period axis splits cleanly into three controller regimes, with the crossover periods
**sliding along the period axis with flap angle** (because the resonance period T₀ shifts):

| Regime | Period band | Winner | Notes |
|--------|-------------|--------|-------|
| **CC** | T ≲ 2 s | **CC** | Near Budal bound; CC peak up to 2.34 W at T=1.5 s (VGM-0) |
| **opt_passive** | ~resonance band | **opt_passive** / tie | Matches tuned ff+PID at resonance with a single tuning-free coefficient |
| **ff+PID** | T ≳ resonance | **ff+PID** | Carries the long tail past resonance with no reactive penalty |

**Crossover periods per flap:**

| Flap | T₀ (resonance) | CC/opt_p xover | opt_p/ff+PID xover |
|------|---------------|----------------|-------------------|
| VGM-90 | ≈2.50 s | ≈1.5–2.0 s | ≈2.5–3.0 s |
| VGM-45 | ≈3.00 s | ≈1.5–2.0 s | ≈3.0–3.5 s |
| VGM-20 | ≈3.25 s | ≈1.5–2.0 s | ≈3.5–4.0 s |
| VGM-10 | ≈3.50 s | ≈1.5–2.0 s | ≈3.5–4.5 s |
| VGM-0 | ≈4.75 s | ≈1.5–2.0 s | ≈4.5–5.5 s |

The flap-angle co-design knob shifts the resonance peak — and therefore the
opt_passive vs ff+PID handoff — across the entire T = 2.5–5 s band. This is the
**controller×geometry co-design operating map**: no single controller or fixed flap
achieves the upper hull; the adaptive (controller, flap-angle) schedule does.

---

## 2. opt_passive resonance hump marches with flap angle

| Flap | opt_passive peak P_capture | peak T | ff+PID peak (passive_guarded) | winner at resonance |
|------|---------------------------|--------|-------------------------------|---------------------|
| VGM-90 | 0.509 W | 2.50 s | ~0.55 W | ff+PID edges |
| VGM-45 | 0.479 W | 3.00 s | ~0.63 W | ff+PID edges |
| VGM-20 | 0.755 W | 3.25 s | ~0.73 W | opt_passive edges |
| VGM-10 | 0.772 W | 3.50 s | ~0.75 W | opt_passive edges |
| VGM-0 | 0.681 W | 4.75 s | ~0.68 W | tie |

The resonance hump monotonically shifts from T ≈ 2.5 s (VGM-90, flap fully open)
to T ≈ 4.75 s (VGM-0, flap closed). This confirms that the intrinsic resonance
T₀ = 2π/ω₀ indeed marches as the flap geometry changes — the hydrodynamic coupling
(radiation damping B55, added inertia A55) all shift together with the flap angle.

### Honest opt_passive vs ff+PID framing

**opt_passive matches a tuned feedforward controller at resonance with a single
tuning-free damping coefficient, and beats CC by 10–30× in the long tail.**

Specifically:
- At the resonance peak: opt_passive **ties-to-slightly-beats** ff+PID on low-angle
flaps (VGM-0/10/20) and ff+PID **edges** opt_passive on high-angle flaps (VGM-45/90).
- The claim is NOT "opt_passive universally wins" — it is that opt_passive achieves
comparable resonance-band performance to a carefully tuned feedforward controller,
with zero per-flap tuning overhead (just one B55-derived coefficient).
- At long periods (T > T₀): ff+PID holds the long tail gracefully; opt_passive drops
off as the off-resonance impedance mismatch grows.

---

## 3. CC validates the Budal bound (short periods)

CC captured power tracks the analytic optimum **P_opt** almost exactly up to
T ≈ 1.5 s. For VGM-0 the CC peak is **2.34 W at T = 1.5 s** with η ≈ 94–108%.
This validates the CC implementation against the Budal/optimal-absorption limit.

At long periods (T ≳ 2 s), CC becomes reactive-heavy
(`|P_injected|/P_converted` → ~0.9). These reactive-heavy "wins" are impractical at
model scale. CC's practical useful range is T ≲ 2 s.

---

## 4. Master operating envelope (co-design capstone)

For each wave period T, the **upper hull = max(P_capture)** over all controllers AND
all flap variants gives the best achievable power from any (controller, flap-angle)
combination.

See `analysis/three_regime/figures/operating_envelope.png` and
`analysis/three_regime/operating_envelope.csv` (hull reproduced from committed CSVs).

**Annotated winner per band:**
- **Short T (≲2 s):** CC + VGM-0 (closed flap, Budal-bound tracking, up to 2.34 W)
- **Resonance band (≈2.5–5 s):** opt_passive or ff+PID + the flap whose T₀ matches
the wave period (90° at T≈2.5 s, marching down to 0° at T≈4.75 s)
- **Long tail (≳5 s):** ff+PID + VGM-0 (low-angle flap holds the longest radiation tail)

No single controller or flap reaches this envelope alone.

---

## 5. Appendix: why fixed-passive was pruned (degenerate arm)

`B_pto = B55(ω₀)` is the radiation damping coefficient at the free-decay resonance.
For all five VGOSWEC flap variants this value is in the range **~1e-4 to ~4e-4 N·m·s/rad**
(with VGM-0 at 3.2e-7, deep in the pitch-radiation notch):

| Flap | B55(ω₀) [N·m·s/rad] | |Z_intrinsic(ω₀)| (approx.) | ratio (approx.) |
|-------|----------------------|---------------------------|-------|
| VGM-0 | 3.19e-7 (pitch notch) | ~1e-2 to 1e-3 | ~10⁴–10⁵× smaller |
| VGM-10 | 1.27e-4 | ~1e-2 | ~100× smaller |
| VGM-20 | 1.51e-4 | ~1e-2 | ~100× smaller |
| VGM-45 | 2.53e-4 | ~1e-2 | ~50× smaller |
| VGM-90 | 3.91e-4 | ~1e-2 | ~25× smaller |

`B_pto = B55(ω₀)` is **10⁴–10⁵× smaller than** `|Z_intrinsic(ω₀)|` that opt_passive
uses as its damping coefficient. A resistive PTO with this tiny coefficient dissipates
essentially zero power against the full intrinsic impedance of the device —
**passive captures ≈ 0 W across the entire T = 0.5–7 s band for all flaps.**

Additionally, B55 has a high-frequency lobe at ω ≈ 8 rad/s, but the flap resonances
span ω ∈ [1.07, 2.09] rad/s (T₀ = 2.99–5.86 s) — so the radiation-damping lobe
never aligns with any flap's operating band. Radiation-damping-matched passive is
degenerate for every VGOSWEC variant.

The `passive` controller type remains available in the code for tank-test tuning
(`config/vgoswec_*_passive.yaml`, `B_pto: 0.5` placeholder, TODO annotation).
It was simply not part of the three-regime study and is excluded from all figures.

---

## Reproducing the figures

```bash
# Three-regime per-flap + cross-flap + operating envelope (from committed CSVs):
python3 scripts/three_regime_comparison.py --plot-only

# Regenerate cc and ff+PID figures independently:
python3 scripts/cc_vs_ffpid_comparison.py --plot-only
python3 scripts/cc_capture_efficiency_sweep.py --plot-only
python3 scripts/capture_efficiency_sweep.py --plot-only
```

Output files:
- `analysis/three_regime/figures/three_regime_VGM{0,10,20,45,90}.png` — per-flap power
- `analysis/three_regime/figures/three_regime_efficiency_VGM{0,10,20,45,90}.png` — efficiency
- `analysis/three_regime/figures/three_regime_summary.png` — cross-flap power summary
- `analysis/three_regime/figures/three_regime_efficiency_summary.png` — cross-flap efficiency
- `analysis/three_regime/figures/operating_envelope.png` — master co-design envelope
- `analysis/three_regime/operating_envelope.csv` — hull data for reproducibility
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 3 additions & 4 deletions config/vgoswec_0_passive.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@ hydro:
wave:
type: regular # regular | jonswap
height: 0.05 # [m] H for regular, Hs for JONSWAP
period: 5.86 # [s] VGM-0 resonance period (WEC-Sim free-decay reference)
period: 1.5 # [s] default wave period
direction: 0.0 # [rad] wave direction (0 = +x)

controller:
type: passive
passive:
# B_pto = B55(ω₀) = 3.1908e-7 N·m·s/rad (radiation damping at free-decay resonance ω₀=1.07 rad/s)
# Computed: λ55(ω₀)·ρ_h5·ω₀ = 2.9820e-10 · 1000.0 · 1.07 (from hydroData/vgoswec_0.h5)
B_pto: 3.1908e-7 # [N·m·s/rad] radiation damping at resonance (very small: VGM-0 pitch notch)
# TODO: tune B_pto with tank-test data
B_pto: 0.5 # [N·m·s/rad] placeholder — tune with tank-test data
clip_torque: 5.0 # [N·m] output saturation limit
7 changes: 3 additions & 4 deletions config/vgoswec_10_passive.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@ hydro:
wave:
type: regular # regular | jonswap
height: 0.05 # [m] H for regular, Hs for JONSWAP
period: 4.29 # [s] VGM-10 resonance period (WEC-Sim free-decay reference)
period: 1.5 # [s] default wave period
direction: 0.0 # [rad] wave direction (0 = +x)

controller:
type: passive
passive:
# B_pto = B55(ω₀) = 1.2723e-4 N·m·s/rad (radiation damping at free-decay resonance ω₀=1.468 rad/s)
# Computed: λ55(ω₀)·ρ_h5·ω₀ = 8.6670e-8 · 1000.0 · 1.468 (from hydroData/vgoswec_10.h5)
B_pto: 1.2723e-4 # [N·m·s/rad] radiation damping at resonance
# TODO: tune B_pto with tank-test data
B_pto: 0.5 # [N·m·s/rad] placeholder — tune with tank-test data
clip_torque: 5.0 # [N·m] output saturation limit
7 changes: 3 additions & 4 deletions config/vgoswec_20_passive.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@ hydro:
wave:
type: regular # regular | jonswap
height: 0.05 # [m] H for regular, Hs for JONSWAP
period: 4.01 # [s] VGM-20 resonance period (WEC-Sim free-decay reference)
period: 1.5 # [s] default wave period
direction: 0.0 # [rad] wave direction (0 = +x)

controller:
type: passive
passive:
# B_pto = B55(ω₀) = 1.5118e-4 N·m·s/rad (radiation damping at free-decay resonance ω₀=1.568 rad/s)
# Computed: λ55(ω₀)·ρ_h5·ω₀ = 9.6416e-8 · 1000.0 · 1.568 (from hydroData/vgoswec_20.h5)
B_pto: 1.5118e-4 # [N·m·s/rad] radiation damping at resonance
# TODO: tune B_pto with tank-test data
B_pto: 0.5 # [N·m·s/rad] placeholder — tune with tank-test data
clip_torque: 5.0 # [N·m] output saturation limit
7 changes: 3 additions & 4 deletions config/vgoswec_45_passive.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ hydro:
wave:
type: regular # regular | jonswap
height: 0.05 # [m] H for regular, Hs for JONSWAP
period: 3.42 # [s] VGM-45 resonance period (WEC-Sim free-decay reference)
period: 1.5 # [s] default wave period
direction: 0.0 # [rad] wave direction (0 = +x)
# JONSWAP-only:
# gamma: 3.3
Expand All @@ -46,7 +46,6 @@ wave:
controller:
type: passive
passive:
# B_pto = B55(ω₀) = 2.5303e-4 N·m·s/rad (radiation damping at free-decay resonance ω₀=1.84 rad/s)
# Computed: λ55(ω₀)·ρ_h5·ω₀ = 1.3752e-7 · 1000.0 · 1.84 (from hydroData/vgoswec_45.h5)
B_pto: 2.5303e-4 # [N·m·s/rad] radiation damping at resonance
# TODO: tune B_pto with tank-test data
B_pto: 0.5 # [N·m·s/rad] placeholder — tune with tank-test data
clip_torque: 5.0 # [N·m] output saturation limit
10 changes: 6 additions & 4 deletions config/vgoswec_90_passive.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@ hydro:
wave:
type: regular # regular | jonswap
height: 0.05 # [m] H for regular, Hs for JONSWAP
period: 2.99 # [s] VGM-90 resonance period (WEC-Sim free-decay reference)
period: 1.5 # [s] default wave period
direction: 0.0 # [rad] wave direction (0 = +x)

controller:
type: passive
passive:
# B_pto = B55(ω₀) = 3.9114e-4 N·m·s/rad (radiation damping at free-decay resonance ω₀=2.094 rad/s)
# Computed: λ55(ω₀)·ρ_h5·ω₀ = 1.8679e-7 · 1000.0 · 2.094 (from hydroData/vgoswec_90.h5)
B_pto: 3.9114e-4 # [N·m·s/rad] radiation damping at resonance
# TODO: tune B_pto with tank-test data
# Note: 0.5 N·m·s/rad is a conservative starting placeholder for tank-test tuning.
# B55(ω₀) at resonance is ~4e-4 N·m·s/rad (far too small to extract meaningful power).
# Use a kpkd sweep or hand-tuning against tank data to find a useful B_pto value.
B_pto: 0.5 # [N·m·s/rad] placeholder — tune with tank-test data
clip_torque: 5.0 # [N·m] output saturation limit
Loading