Add constraint highlighting
This commit is contained in:
110
CLAUDE.md
110
CLAUDE.md
@@ -4,24 +4,39 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
This is a Python-based transformer modeling toolkit for electrical power transformers. It contains two distinct transformer models and an optimizer:
|
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. **Simple Ideal Model** ([model.py](model.py)) - Physics-based model for transformers with taps, calculates flux density, losses, and efficiency
|
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. **Optimizer** ([optimizer.py](optimizer.py)) - Finds optimal tap settings and input voltage to maximize efficiency for a given load and target power
|
2. **Simulator** ([sim_toroid.py](sim_toroid.py)) - Evaluates operating points (flux density, currents, losses, efficiency) and sweeps across frequency/load combinations
|
||||||
3. **Impedance-Based Model** ([old/transformer_model.py](old/transformer_model.py)) - Uses measured open-circuit and short-circuit parameters for AC analysis
|
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
|
## Commands
|
||||||
|
|
||||||
### Running Simulations
|
### Running the Web App
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run the simple transformer model with optimizer example (requires numpy)
|
# 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
|
python sim.py
|
||||||
|
|
||||||
# Run the per-segment resistance example
|
# Run the per-segment resistance example
|
||||||
python example_per_segment_resistance.py
|
python example_per_segment_resistance.py
|
||||||
|
|
||||||
# Run the impedance-based model example (requires numpy)
|
# Run the impedance-based model example
|
||||||
python old/run_model_example.py
|
python old/run_model_example.py
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -34,47 +49,72 @@ python old/run_model_example.py
|
|||||||
|
|
||||||
# Activate it (Unix/Mac):
|
# Activate it (Unix/Mac):
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
|
|
||||||
|
# Install dependencies:
|
||||||
|
pip install -r requirements.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
## Code Architecture
|
## Code Architecture
|
||||||
|
|
||||||
### Simple Model (model.py)
|
### Web App (app.py)
|
||||||
|
|
||||||
- **TransformerModel** class: Dataclass-based model with:
|
Flask server with these routes:
|
||||||
- Core geometry parameters (Ae_mm2)
|
|
||||||
- Turn counts and tap positions for primary/secondary windings
|
|
||||||
- Copper resistance per turn (supports both uniform and per-segment values)
|
|
||||||
- `simulate()` method: Calculates one operating point given tap number, voltage, frequency, and load
|
|
||||||
- Returns flux density (B_peak_T), currents, powers, and efficiency
|
|
||||||
|
|
||||||
**Key concept**: Taps are defined as lists of **incremental turns** for each segment. First element is always 0, subsequent elements specify turns to add. Example: `[0, 128, 23]` means segment 1 adds 128 turns, segment 2 adds 23 turns. Tap numbers are 1-indexed: `tap=1` gives 128 turns, `tap=2` gives 128+23=151 turns total.
|
| 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/<type>` | GET | Lists saved presets for a category |
|
||||||
|
| `/api/presets/<type>/<name>` | GET/POST/DELETE | Load, save, or delete a named preset |
|
||||||
|
|
||||||
**Per-segment resistance**: For windings with different wire gauges per segment, use `primary_Rp_per_turn` and `secondary_Rs_per_turn` lists. Each element specifies R/turn for that segment (e.g., `[0.001, 0.002]` for a 2-segment winding). Legacy single-value `Rp_per_turn`/`Rs_per_turn` still supported.
|
Preset categories: `core`, `windings`, `constraints`, `sim`. Presets are persisted as JSON files in the `presets/` directory.
|
||||||
|
|
||||||
### Optimizer (optimizer.py)
|
### Designer (designer.py)
|
||||||
|
|
||||||
- **TransformerOptimizer** class: Brute-force search optimizer
|
- **ToroidCore** dataclass: core geometry (`ID_mm`, `OD_mm`, `height_mm`, `Ae_mm2`, `Ve_mm3`, optional `Pv_func`)
|
||||||
- `optimize()` method: Searches all tap combinations and voltage sweep to find maximum efficiency
|
- **WindingSpec** dataclass: `awg` (list of AWG per segment), `taps` (incremental turns list), `name`
|
||||||
- Constraints: Target power delivery (with tolerance), maximum flux density (B_max_T), maximum secondary voltage (Vs_max), input voltage range
|
- **WireSpec** dataclass: wire diameter (with insulation), resistance/m, weight/m; look up via `WireSpec.from_awg(awg)`
|
||||||
- Returns **OptimizationResult** with optimal configuration and all operating point details
|
- **WindingResult** dataclass: per-segment results (`SegmentResult`) including layers, wire length, resistance, weight, fits flag
|
||||||
- **Fallback mode** (default): If target power cannot be achieved, finds max achievable power with best efficiency
|
- `design_transformer(core, specs, fill_factor)`: returns list of `WindingResult`
|
||||||
|
|
||||||
**Key concept**: For a given load and target power, the optimizer tries all possible tap combinations and input voltages to find the configuration that maximizes efficiency while meeting all constraints (power delivery, flux density, and secondary voltage).
|
**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)
|
### Impedance Model (old/transformer_model.py)
|
||||||
|
|
||||||
- **TransformerModel** class: Interpolates measured OC/SC test data
|
- **TransformerModel**: interpolates measured OC/SC test data; frequency-dependent Rc/Lm; per-tap Req/L_leak
|
||||||
- Frequency-dependent Rc and Lm from open-circuit tests
|
- `input_impedance()`, `transfer()` for AC analysis
|
||||||
- Per-tap series impedance (Req, L_leak) from short-circuit tests
|
|
||||||
- `input_impedance()`: Calculates Zin at frequency/tap/load
|
|
||||||
- `transfer()`: Full AC transfer function with powers and efficiency
|
|
||||||
|
|
||||||
**Key concept**: Model uses complex impedance networks with reflected loads through turns ratios.
|
|
||||||
|
|
||||||
## Important Implementation Details
|
## Important Implementation Details
|
||||||
|
|
||||||
- Both models assume **purely resistive loads**
|
- Loads are specified as complex impedance `(R, X)` pairs in ohms
|
||||||
- Simple model uses **sinusoidal excitation** (4.44*f formula for flux density)
|
- Flux density uses sinusoidal formula: `B_peak = Vp / (4.44 * f * N * Ae)`
|
||||||
- Impedance model supports **source resistance** and secondary winding resistance per tap
|
- Core loss uses `Pv_func(f_hz, B_T)` if provided, else a simple Steinmetz fallback
|
||||||
- Tap numbering: Both models use 1-indexed taps (tap=1, tap=2, etc.)
|
- Tap numbering is 1-indexed throughout
|
||||||
- The `old/` directory contains the earlier impedance-based approach with example sweep functionality
|
- 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`)
|
||||||
|
|||||||
2
app.py
2
app.py
@@ -461,4 +461,4 @@ def presets_delete(ptype: str, name: str):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(debug=True, host="0.0.0.0", port=5000)
|
app.run(debug=True, host="0.0.0.0", port=5010)
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
flask>=2.3.0
|
flask>=2.3.0
|
||||||
numpy>=1.24.0
|
numpy>=1.24.0
|
||||||
|
matplotlib>=3.7.0
|
||||||
|
|||||||
Reference in New Issue
Block a user