# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is a Python/Flask web application for designing and simulating toroidal transformers. It provides a browser-based UI backed by several physics modules: 1. **Designer** ([designer.py](designer.py)) - Computes winding feasibility, layer counts, wire lengths, DC resistance, and weight for each winding segment given core geometry and wire specs 2. **Simulator** ([sim_toroid.py](sim_toroid.py)) - Evaluates operating points (flux density, currents, losses, efficiency) and sweeps across frequency/load combinations 3. **Drawing** ([draw_toroid.py](draw_toroid.py)) - Renders a top-down axial cross-section of the toroid (wire dots in bore, core annulus) as a PNG via matplotlib 4. **Web App** ([app.py](app.py)) - Flask server exposing REST API routes consumed by the browser UI 5. **Legacy simple model** ([model.py](model.py)) - Earlier physics-based model (taps, flux density, losses); still present but not used by the web app 6. **Legacy optimizer** ([optimizer.py](optimizer.py)) - Brute-force tap/voltage optimizer for the legacy model 7. **Impedance-Based Model** ([old/transformer_model.py](old/transformer_model.py)) - Uses measured open-circuit and short-circuit parameters for AC analysis ## Commands ### Running the Web App ```bash # Activate venv first (Unix/Mac): source .venv/bin/activate # Start the Flask dev server (port 5010): python app.py # Then open http://localhost:5010 in a browser ``` ### Running Legacy Simulations ```bash # Run the simple transformer model with optimizer example python sim.py # Run the per-segment resistance example python example_per_segment_resistance.py # Run the impedance-based model example python old/run_model_example.py ``` ### Development Environment ```bash # Virtual environment exists at .venv # Activate it (Windows): .venv\Scripts\activate # Activate it (Unix/Mac): source .venv/bin/activate # Install dependencies: pip install -r requirements.txt ``` ## Code Architecture ### Web App (app.py) Flask server with these routes: | Route | Method | Description | |---|---|---| | `GET /` | GET | Serves the main HTML page (`templates/index.html`) | | `/api/design` | POST | Runs `design_transformer()`, returns winding info + PNG drawing (base64) | | `/api/simulate` | POST | Computes a single operating point via `ToroidSimulator.simulate()` | | `/api/sweep` | POST | Runs `sweep_operating_points()` over a grid of frequencies × loads | | `/api/presets/` | GET | Lists saved presets for a category | | `/api/presets//` | GET/POST/DELETE | Load, save, or delete a named preset | Preset categories: `core`, `windings`, `constraints`, `sim`. Presets are persisted as JSON files in the `presets/` directory. ### Designer (designer.py) - **ToroidCore** dataclass: core geometry (`ID_mm`, `OD_mm`, `height_mm`, `Ae_mm2`, `Ve_mm3`, optional `Pv_func`) - **WindingSpec** dataclass: `awg` (list of AWG per segment), `taps` (incremental turns list), `name` - **WireSpec** dataclass: wire diameter (with insulation), resistance/m, weight/m; look up via `WireSpec.from_awg(awg)` - **WindingResult** dataclass: per-segment results (`SegmentResult`) including layers, wire length, resistance, weight, fits flag - `design_transformer(core, specs, fill_factor)`: returns list of `WindingResult` **Tap format**: `taps` is a list of incremental turns. `[0, 25, 50]` means segment 1 = 25 turns, segment 2 = 50 turns; total turns = 75. Tap numbers are 1-indexed. ### Simulator (sim_toroid.py) - **SimConstraints** dataclass: `B_max_T`, `Vp_max`, `Vs_max`, `Ip_max`, `Is_max`, `P_out_max_W` - **ToroidSimulator**: takes `ToroidCore`, primary `WindingResult`, secondary `WindingResult` - `simulate(Vp_rms, freq_hz, primary_tap, secondary_tap, Z_load, constraints)` → `SimResult` - `SimResult` fields: `Np_eff`, `Ns_eff`, `turns_ratio`, `B_peak_T`, `Vp_rms_applied`, `Vs_rms`, `Ip_rms`, `Is_rms`, `P_out_W`, `P_cu_W`, `P_cu_primary_W`, `P_cu_secondary_W`, `P_core_W`, `P_in_W`, `efficiency`, `violations` - **SweepEntry** / `sweep_operating_points()`: sweeps all tap combinations over a frequency × load grid, finding the best tap pair for each condition at the target power - `SweepEntry.as_dict()` serialises to a flat dict for JSON responses ### Drawing (draw_toroid.py) - `draw_toroid(core, results, output_path, dpi, fig_size_mm, actual_fill)`: renders top-down cross-section PNG using matplotlib - View: looking down the toroid axis. Grey annulus = core; white disc = bore; coloured dots = wire cross-sections per winding/layer ### Legacy Simple Model (model.py) - **TransformerModel** dataclass: core area (`Ae_mm2`), turn counts, tap lists, per-turn resistance (uniform or per-segment) - `simulate(tap, Vp, freq, R_load)` → flux density, currents, powers, efficiency ### Legacy Optimizer (optimizer.py) - **TransformerOptimizer**: brute-force search over all tap combinations + voltage sweep - Returns **OptimizationResult** with optimal tap/voltage configuration ### Impedance Model (old/transformer_model.py) - **TransformerModel**: interpolates measured OC/SC test data; frequency-dependent Rc/Lm; per-tap Req/L_leak - `input_impedance()`, `transfer()` for AC analysis ## Important Implementation Details - Loads are specified as complex impedance `(R, X)` pairs in ohms - Flux density uses sinusoidal formula: `B_peak = Vp / (4.44 * f * N * Ae)` - Core loss uses `Pv_func(f_hz, B_T)` if provided, else a simple Steinmetz fallback - Tap numbering is 1-indexed throughout - The `old/` directory contains the earlier impedance-based approach - `presets/` directory is auto-created; stores JSON files (`core.json`, `windings.json`, `constraints.json`, `sim.json`)