Skip to content

Commit e3506e6

Browse files
transformer plan
1 parent 1d6c771 commit e3506e6

3 files changed

Lines changed: 393 additions & 3 deletions

File tree

AGENTS.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pyvibrate/
88
frequencydomain/ # COMPLETE - Steady-state AC analysis
99
```
1010

11-
## Frequency-Domain Module (Complete)
11+
## Frequency-Domain Module (Usably Complete)
1212

1313
### Components Implemented
1414

@@ -36,6 +36,28 @@ pyvibrate/
3636
- `demo_freqdomain_fitting.ipynb` - Parameter identification (fit capacitor ESR/ESL/C to noisy data)
3737
- `demo_delay_line.ipynb` - Delay line in both domains: time-domain with FFT, freq-domain with iFFT
3838

39+
### Current Work: Realistic Transformer Component
40+
41+
**Status:** Planning complete, ready for implementation
42+
43+
**Detailed Plan:** See `AGENTS_realistic_transformer_plan.md`
44+
45+
**Goal:** Frequency-domain transformer with physical parameters (N1, N2, A_core, l_m, mu_r, B_sat) and VNA extraction notebook
46+
47+
**Key Features:**
48+
- Y-parameter 2-port stamping (similar to TLine)
49+
- Equivalent circuit: magnetizing inductance, core loss, leakage, winding resistance
50+
- Linear solver with post-solve saturation warnings
51+
- Four VNA tests: open circuit, short circuit, loaded, and saturation curve extraction
52+
53+
**Implementation Phases:**
54+
1. Core component: physical_constants.py, Transformer() factory, MNA stamping
55+
2. Testing: 10 unit tests validating all aspects
56+
3. Saturation warning: check_transformer_saturation() helper
57+
4. VNA notebook: comprehensive parameter extraction tutorial
58+
59+
**Next Steps:** Begin Phase 1 (core component implementation)
60+
3961
### Future Work
4062
- Frequency sweep helper function
4163
- S-parameter calculation for VNA fitting
Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
# Realistic Transformer Component Implementation Plan
2+
3+
## Overview
4+
5+
Implement a physically-accurate transformer component for PyVibrate's frequency domain solver with:
6+
- Physical parameter interface (N1, N2, A_core, l_m, mu_r, B_sat)
7+
- Realistic equivalent circuit (magnetizing inductance, core loss, leakage, winding resistance)
8+
- Linear operation with saturation warnings
9+
- Comprehensive VNA parameter extraction notebook
10+
11+
## Implementation Approach
12+
13+
### Component Architecture: Single Component with Internal Y-Parameter Stamping
14+
15+
**Rationale:** Simplest user interface, optimal for parameter fitting, JAX-compatible, follows existing TLine pattern.
16+
17+
**Equivalent Circuit Model:**
18+
```
19+
Primary: n_p_pos ──[R1]──[L_leak1]──┬──[L_mag║R_core]──║ n:1 ║──┬──[L_leak2]──[R2]── n_s_pos
20+
│ │
21+
Secondary: n_p_neg ──────────────────┴─────────────────║ ║──┴────────────────── n_s_neg
22+
```
23+
24+
### Physical Parameters → Circuit Parameters
25+
- `L1 = μ₀ * μᵣ * N1² * A_core / l_m` (primary inductance)
26+
- `L2 = μ₀ * μᵣ * N2² * A_core / l_m` (secondary inductance)
27+
- `M = k * sqrt(L1 * L2)` (mutual inductance, k = coupling coefficient)
28+
- `L_mag = k * L1` (magnetizing inductance)
29+
- `L_leak1 = (1-k) * L1`, `L_leak2 = (1-k) * L2` (leakage inductances)
30+
31+
### MNA Stamping Strategy
32+
33+
Transform equivalent circuit to 2-port Z-parameters:
34+
```
35+
Z11 = R1 + jωL_leak1 + (jωL_mag ║ R_core)
36+
Z22 = R2 + jωL_leak2
37+
Z12 = Z21 = jωM
38+
```
39+
40+
Convert to Y-parameters via 2×2 matrix inversion:
41+
```
42+
det = Z11*Z22 - Z12*Z21
43+
Y11 = Z22/det, Y12 = -Z12/det
44+
Y21 = -Z21/det, Y22 = Z11/det
45+
```
46+
47+
Stamp using existing `_stamp_2port_admittance()` helper.
48+
49+
### Saturation Warning (Post-Solve)
50+
51+
After each solve, optionally check saturation:
52+
```python
53+
def check_transformer_saturation(solution, transformer_ref, params):
54+
# Estimate magnetizing current from primary voltage
55+
I_mag = V_prim / (jωL_mag)
56+
57+
# Compute flux density
58+
B = μ₀ * μᵣ * N1 * |I_mag| / l_m
59+
60+
# Compare to B_sat
61+
return {
62+
"B_current": B,
63+
"B_sat": B_sat,
64+
"utilization": B/B_sat,
65+
"warning": B/B_sat > 0.8
66+
}
67+
```
68+
69+
**Note:** Approximation only - doesn't account for load current. Document as order-of-magnitude check.
70+
71+
## Files to Create/Modify
72+
73+
### New Files
74+
75+
1. **`pyvibrate/frequencydomain/physical_constants.py`** (~100 lines)
76+
- Physical constants: `MU_0 = 4π×10⁻⁷ H/m`
77+
- Core material database (ferrite, powder iron, silicon steel)
78+
- Helper functions:
79+
- `compute_inductance(N, A_core, l_m, mu_r) -> L`
80+
- `compute_flux_density(I, N, l_m, mu_r) -> B`
81+
- `tanh_core_model(H, H_c, B_sat)` (reference for future nonlinear work)
82+
83+
2. **`tests/test_freqdomain_transformer.py`** (~300 lines)
84+
- 10 unit tests covering:
85+
- Turns ratio (n:1 voltage transformation)
86+
- Impedance transformation (Z_in = n²*Z_load)
87+
- Open circuit test (measure L_mag)
88+
- Short circuit test (measure L_leak)
89+
- Coupling coefficient effect
90+
- Core loss effect on efficiency
91+
- Physical parameter computation
92+
- Saturation warning logic
93+
- JAX differentiability
94+
- Frequency response
95+
96+
3. **`notebooks/demo_transformer_vna_extraction.ipynb`** (~500 lines)
97+
- **Section 1: Open Circuit Test**
98+
- Theory: secondary open, Z_in ≈ R1 + jωL_mag + R_core effects
99+
- Generate synthetic measurement data
100+
- Extract L_mag and R_core from frequency sweep
101+
- Plot impedance magnitude and phase vs frequency
102+
103+
- **Section 2: Short Circuit Test**
104+
- assume the turn count is known on both sides
105+
- Theory: secondary shorted, Z_in ≈ R1 + R2/n² + jω(L_leak1 + L_leak2/n²)
106+
- Extract total leakage inductance and winding resistance
107+
- Compare measured to computed from coupling coefficient k
108+
- Assume the turn count is known on both sides
109+
110+
- **Section 3: Loaded Test**
111+
- assume the turn count is known on both sides
112+
- Sweep multiple load resistances (10Ω to 500Ω)
113+
- Measure Z_in(R_load) at fixed frequency
114+
- Compute coupling coefficient k from measurements
115+
116+
- **Section 4: Inductance vs DC Bias (Saturation Curve)**
117+
- Simulate L(I) using reduced μᵣ at each DC bias point
118+
- Fit to tanh model: `B = B_sat * tanh(H/H_c)`
119+
- Extract B_sat and H_c parameters
120+
- Plot L vs I showing saturation onset
121+
- **Note:** Demonstrates characterization concept even though solver is linear
122+
123+
### Modified Files
124+
125+
1. **`pyvibrate/frequencydomain/components.py`** (+80 lines)
126+
```python
127+
def Transformer(
128+
net: Network,
129+
prim_pos: Node, prim_neg: Node,
130+
sec_pos: Node, sec_neg: Node,
131+
*,
132+
name: str,
133+
# Physical parameters
134+
N1: float | None = None, # Primary turns
135+
N2: float | None = None, # Secondary turns
136+
A_core: float | None = None, # Core area (m²)
137+
l_m: float | None = None, # Mean path length (m)
138+
mu_r: float | None = None, # Relative permeability
139+
B_sat: float | None = None, # Saturation flux (T)
140+
# Circuit parameters
141+
k: float = 0.98, # Coupling coefficient
142+
R1: float | None = None, # Primary resistance
143+
R2: float | None = None, # Secondary resistance
144+
R_core: float | None = None, # Core loss resistance
145+
) -> tuple[Network, ComponentRef]:
146+
```
147+
148+
Store all parameters in defaults tuple using suffix pattern: `{name}_N1`, `{name}_A_core`, etc.
149+
150+
2. **`pyvibrate/frequencydomain/solver.py`** (+60 lines)
151+
- Add `"Transformer"` case to `_stamp_component()`:
152+
- Extract physical parameters from params dict
153+
- Compute L1, L2, M from N1, N2, A_core, l_m, mu_r
154+
- Build Z-parameters with series/parallel elements
155+
- Convert to Y-parameters (2×2 inversion with det safety check)
156+
- Stamp using `_stamp_2port_admittance()`
157+
158+
- Add `check_transformer_saturation()` helper to Solver class:
159+
- Takes (solution, component_ref, params) → dict
160+
- Returns saturation metrics and warning flags
161+
- Non-invasive, optional post-solve check
162+
163+
3. **`pyvibrate/frequencydomain/__init__.py`** (+2 lines)
164+
- Export `Transformer` in `__all__`
165+
- Export `physical_constants` module
166+
167+
## Critical Implementation Details
168+
169+
### Edge Case Handling
170+
171+
1. **DC operation (ω=0):**
172+
```python
173+
omega_safe = jnp.where(omega < 1e-6, 1e-6, omega)
174+
```
175+
176+
2. **Determinant safety (at resonance):**
177+
```python
178+
det = Z11*Z22 - Z12*Z21
179+
det_safe = jnp.where(jnp.abs(det) < 1e-15, 1e-15, det)
180+
```
181+
182+
3. **Coupling coefficient bounds:**
183+
```python
184+
k = jnp.clip(k, 0.5, 0.9999)
185+
```
186+
187+
### JAX Differentiability
188+
189+
- Use `jnp.where()` for all conditionals (no Python `if`)
190+
- All computations in stamping loop (not component factory)
191+
- Test gradients w.r.t. all physical parameters
192+
193+
### Parameter Extraction Strategy (VNA Notebook)
194+
195+
**Sequential extraction avoids ill-conditioning:**
196+
1. Open circuit → L_mag (independent)
197+
2. Short circuit → L_leak_total (independent)
198+
3. Loaded test → n, k (coupled but constrained)
199+
4. Compute R_core, R1, R2 from loss measurements
200+
201+
**Better than full gradient descent:** Each parameter isolated to specific test.
202+
203+
## Testing Strategy
204+
205+
### Unit Test Hierarchy
206+
1. **Basic transformer behavior** (turns ratio, impedance transform)
207+
2. **VNA test validation** (open, short, loaded match theory)
208+
3. **Physical parameter computation** (N, A → L correct)
209+
4. **Edge cases** (DC, high frequency, saturation)
210+
5. **JAX compatibility** (gradients finite, vmap works)
211+
212+
### Validation Sources
213+
- Hand-calculated Z-parameters for simple cases
214+
- Published transformer datasheets (compare to real devices)
215+
- Cross-check with LTspice (if needed for complex cases)
216+
217+
## Implementation Sequence
218+
219+
### Phase 1: Core Component (Priority 1)
220+
1. Create `physical_constants.py` with μ₀, compute functions
221+
2. Add `Transformer()` factory to `components.py`
222+
3. Add stamping case to `solver.py`
223+
4. Update `__init__.py` exports
224+
5. Write 3 basic tests (turns ratio, impedance, open circuit)
225+
226+
### Phase 2: Testing & Validation (Priority 1)
227+
6. Write remaining 7 unit tests
228+
7. Validate against hand calculations
229+
8. Fix bugs, stabilize numerics
230+
231+
### Phase 3: Saturation Warning (Priority 2)
232+
9. Implement `check_transformer_saturation()`
233+
10. Add saturation test
234+
11. Document approximations and limitations
235+
236+
### Phase 4: VNA Notebook (Priority 2)
237+
12. Create notebook skeleton with 4 sections
238+
13. Implement open circuit extraction
239+
14. Implement short circuit extraction
240+
15. Implement loaded test extraction
241+
16. Implement saturation curve extraction
242+
17. Add explanatory markdown, theory sections
243+
244+
### Phase 5: Documentation (Priority 3)
245+
18. Complete all docstrings
246+
19. Add transformer example to README
247+
20. Create simple application example (e.g., flyback converter)
248+
249+
## Success Criteria
250+
251+
**Functional:**
252+
- [ ] Transformer compiles and solves at all frequencies
253+
- [ ] All 10 unit tests pass with <1% error
254+
- [ ] JAX gradients finite for all parameters
255+
- [ ] VNA notebook runs end-to-end
256+
- [ ] Parameter extraction accuracy <5% on synthetic data
257+
258+
**Quality:**
259+
- [ ] Follows existing PyVibrate patterns (factory functions, stamping)
260+
- [ ] No performance regression (solve time <2× baseline)
261+
- [ ] Docstrings complete with equations
262+
- [ ] Notebook is tutorial-quality with clear explanations
263+
264+
**Documentation:**
265+
- [ ] Equivalent circuit diagram in docstring
266+
- [ ] Physical parameter formulas documented
267+
- [ ] VNA test theory explained
268+
- [ ] Saturation warning limitations noted
269+
270+
## Known Limitations (to Document)
271+
272+
1. **Linear solver only** - saturation effects not modeled in solve loop
273+
2. **Saturation warning is approximate** - uses primary voltage, ignores load current
274+
3. **No hysteresis** - single-valued B-H curve (tanh model)
275+
4. **Frequency domain only** - no time-domain transformer yet
276+
5. **Ideal coupling** - no frequency-dependent losses or skin effect
277+
278+
These are acceptable for the initial implementation and clearly documented.
279+
280+
## Reference Files
281+
282+
Key files for implementation patterns:
283+
- `/home/mib07150/git/zfs/git/private/20251203-pyvibrate/pyvibrate/frequencydomain/solver.py:264-283` - TLine Y-parameter stamping
284+
- `/home/mib07150/git/zfs/git/private/20251203-pyvibrate/pyvibrate/frequencydomain/components.py:140-165` - ConstantTimeDelayVCVS multi-parameter pattern
285+
- `/home/mib07150/git/zfs/git/private/20251203-pyvibrate/tests/test_freqdomain_l.py` - Inductor test patterns
286+
- `/home/mib07150/git/zfs/git/private/20251203-pyvibrate/notebooks/demo_freqdomain_fitting.ipynb` - Parameter extraction patterns

0 commit comments

Comments
 (0)