added toroid simulator
This commit is contained in:
59
designer.py
59
designer.py
@@ -279,7 +279,7 @@ class WindingResult:
|
||||
# Internal winding position at end of this winding (for chaining)
|
||||
_end_layer: int = 0
|
||||
_end_turns_in_layer: int = 0
|
||||
_end_total_turns: int = 0
|
||||
_end_consumed_area_mm2: float = 0.0
|
||||
|
||||
def summary(self) -> str:
|
||||
# Header: show AWG as single value if uniform, else show range
|
||||
@@ -372,7 +372,8 @@ def analyse_winding(
|
||||
fill_factor: float = 0.35,
|
||||
start_layer: int = 0,
|
||||
start_turns_in_layer: int = 0,
|
||||
start_total_turns: int = 0,
|
||||
consumed_area_mm2: float = 0.0,
|
||||
budget_area_mm2: Optional[float] = None,
|
||||
) -> WindingResult:
|
||||
"""
|
||||
Analyse feasibility and compute wire parameters for a winding.
|
||||
@@ -389,9 +390,13 @@ def analyse_winding(
|
||||
_end_layer to continue mid-layer across windings.
|
||||
start_turns_in_layer : int
|
||||
Turns already consumed in start_layer from a previous winding.
|
||||
start_total_turns : int
|
||||
Cumulative turns already placed (used for fill-factor accounting
|
||||
across windings).
|
||||
consumed_area_mm2 : float
|
||||
Wire cross-section area (mm²) already consumed by previous windings.
|
||||
Fill-factor budget is tracked in area so mixed gauges are handled
|
||||
correctly.
|
||||
budget_area_mm2 : float or None
|
||||
Total allowed wire area (fill_factor * window_area). Computed from
|
||||
fill_factor if not supplied.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -415,7 +420,8 @@ def analyse_winding(
|
||||
max_turns_geometry += cap
|
||||
layer_idx += 1
|
||||
|
||||
effective_max = max_turns_fill # fill factor is the binding constraint
|
||||
if budget_area_mm2 is None:
|
||||
budget_area_mm2 = fill_factor * core.window_area_mm2
|
||||
|
||||
segments: list[SegmentResult] = []
|
||||
overall_feasible = True
|
||||
@@ -424,7 +430,6 @@ def analyse_winding(
|
||||
# turns have been placed in the current layer already.
|
||||
current_layer = start_layer
|
||||
turns_in_current_layer = start_turns_in_layer
|
||||
total_turns_placed = start_total_turns
|
||||
current_layer_wire_diameter: Optional[float] = None # set on first use
|
||||
|
||||
for seg_idx, (seg_turns, wire) in enumerate(zip(spec.segment_turns(), seg_wires)):
|
||||
@@ -432,6 +437,7 @@ def analyse_winding(
|
||||
seg_wire_length_mm = 0.0
|
||||
seg_fits = True
|
||||
turns_remaining = seg_turns
|
||||
wire_area = math.pi * (wire.diameter_mm / 2.0) ** 2
|
||||
|
||||
while turns_remaining > 0:
|
||||
# If the wire gauge changed from what's already on this layer,
|
||||
@@ -449,7 +455,6 @@ def analyse_winding(
|
||||
# No more geometry room at all
|
||||
seg_fits = False
|
||||
overall_feasible = False
|
||||
# Record overflow as a single "layer" with 0 capacity
|
||||
seg_layers.append(LayerResult(
|
||||
layer_index=current_layer,
|
||||
turns_capacity=0,
|
||||
@@ -467,8 +472,11 @@ def analyse_winding(
|
||||
turns_in_current_layer = 0
|
||||
continue
|
||||
|
||||
# Check fill-factor cap
|
||||
if total_turns_placed >= effective_max:
|
||||
# Fill-factor check: how many more turns of this gauge fit in budget?
|
||||
area_remaining = budget_area_mm2 - consumed_area_mm2
|
||||
turns_by_fill = int(area_remaining / wire_area) if wire_area > 0 else 0
|
||||
|
||||
if turns_by_fill <= 0:
|
||||
seg_fits = False
|
||||
overall_feasible = False
|
||||
seg_layers.append(LayerResult(
|
||||
@@ -481,9 +489,7 @@ def analyse_winding(
|
||||
turns_remaining = 0
|
||||
break
|
||||
|
||||
turns_to_place = min(turns_remaining,
|
||||
available_in_layer,
|
||||
effective_max - total_turns_placed)
|
||||
turns_to_place = min(turns_remaining, available_in_layer, turns_by_fill)
|
||||
wire_len = turns_to_place * L_turn
|
||||
|
||||
seg_layers.append(LayerResult(
|
||||
@@ -497,7 +503,7 @@ def analyse_winding(
|
||||
seg_wire_length_mm += wire_len
|
||||
turns_remaining -= turns_to_place
|
||||
turns_in_current_layer += turns_to_place
|
||||
total_turns_placed += turns_to_place
|
||||
consumed_area_mm2 += turns_to_place * wire_area
|
||||
|
||||
if turns_in_current_layer >= cap:
|
||||
current_layer += 1
|
||||
@@ -549,7 +555,7 @@ def analyse_winding(
|
||||
cost_usd=cost_usd,
|
||||
_end_layer=current_layer,
|
||||
_end_turns_in_layer=turns_in_current_layer,
|
||||
_end_total_turns=total_turns_placed,
|
||||
_end_consumed_area_mm2=consumed_area_mm2,
|
||||
)
|
||||
|
||||
|
||||
@@ -582,39 +588,24 @@ def design_transformer(
|
||||
results: list[WindingResult] = []
|
||||
cur_layer = 0
|
||||
cur_turns_in_layer = 0
|
||||
# Track consumed window area (mm²) across all windings to enforce the
|
||||
# shared fill-factor budget regardless of AWG.
|
||||
consumed_area_mm2 = 0.0
|
||||
budget_area_mm2 = fill_factor * core.window_area_mm2
|
||||
|
||||
for spec in windings:
|
||||
# Use the thickest wire in this spec for area-budget accounting
|
||||
seg_wires = [WireSpec.from_awg(a) for a in spec.awg]
|
||||
wire_ref = max(seg_wires, key=lambda w: w.diameter_mm)
|
||||
wire_area_mm2 = math.pi * (wire_ref.diameter_mm / 2.0) ** 2
|
||||
# Express the remaining area budget as an equivalent turn count for
|
||||
# this winding's reference wire gauge, then back-calculate the
|
||||
# synthetic start offset so that analyse_winding's fill-factor
|
||||
# headroom check is correct.
|
||||
turns_already_equivalent = int(consumed_area_mm2 / wire_area_mm2)
|
||||
|
||||
result = analyse_winding(
|
||||
core=core,
|
||||
spec=spec,
|
||||
fill_factor=fill_factor,
|
||||
start_layer=cur_layer,
|
||||
start_turns_in_layer=cur_turns_in_layer,
|
||||
start_total_turns=turns_already_equivalent,
|
||||
consumed_area_mm2=consumed_area_mm2,
|
||||
budget_area_mm2=budget_area_mm2,
|
||||
)
|
||||
results.append(result)
|
||||
|
||||
# Advance shared layer position
|
||||
cur_layer = result._end_layer
|
||||
cur_turns_in_layer = result._end_turns_in_layer
|
||||
# Update consumed area using actual turns placed in this winding
|
||||
turns_placed = result._end_total_turns - turns_already_equivalent
|
||||
consumed_area_mm2 = min(budget_area_mm2,
|
||||
consumed_area_mm2 + turns_placed * wire_area_mm2)
|
||||
consumed_area_mm2 = result._end_consumed_area_mm2
|
||||
|
||||
return results
|
||||
|
||||
@@ -633,7 +624,7 @@ if __name__ == "__main__":
|
||||
)
|
||||
|
||||
secondary = WindingSpec(
|
||||
awg=[22, 22, 22, 26], # uniform gauge
|
||||
awg=[22, 22, 22, 28], # uniform gauge
|
||||
taps=[0, 100, 50, 50, 50],
|
||||
name="secondary",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user