This file is the SINGLE SOURCE OF TRUTH for any AI agent using PyOpenMagnetics. Every instruction was derived from reading the C++ source code (
converter.cpp,magnetics.cpp,cores.cpp,wires.cpp,settings.cpp,database.cpp,CoreAdviser.h/.cpp,MagneticAdviser.h/.cpp,MAS.hpp,Flyback.h/.cpp, all converter model headers, and all adviser files) and validated by running the library.When this document contradicts the
.pyistubs or bundled examples, trust this document.
Before writing ANY code, check these three things:
-
NEVER use
json.dumps()— Pass Python dicts directly to all functions.json.dumps()converts your dict to a string, causing schema errors. -
NEVER invent your own JSON structure — Copy the EXACT schemas from Section 5. Fields like
"inputs","outputs","voltage"are WRONG. Use"inputVoltage","operatingPoints", etc. -
NEVER abandon Method A after an error — If you get
"Input JSON does not conform to schema!", the fix is to correct your JSON, NOT to fall back to manual calculations.
See Section 13.1 for wrong vs correct code examples.
When a user asks you to design a magnetic component for a power converter:
- ALWAYS use
design_magnetics_from_converter()first (Method A — single call) - If Method A fails (e.g., ngspice cannot initialize), fall back to
process_converter()→calculate_advised_magnetics()(Method B) - NEVER calculate turns ratios, inductance, core sizes, or wire gauges manually
- NEVER fall back to textbook formulas — fix the API call instead
The MKF engine handles complex magnetic field distributions, temperature-dependent material properties, geometrical fringing effects, and real commercial core database constraints that manual formulas cannot replicate.
If Method A times out, this is NOT a reason to switch to Method B.
The design computation is CPU-intensive:
"available cores"searches 1301+ shapes and can take 60â€"180+ seconds"standard cores"is faster (10â€"30 seconds) but has fewer options
If your environment has a short timeout (e.g., 2â€"3 minutes):
- First try: Use
"standard cores"instead of"available cores"â€" this is much faster - If still timing out: Increase your timeout to 5+ minutes, NOT switch to Method B
- Only use Method B if Method A returns an actual error (schema error, ngspice failure, etc.)
# ✅ CORRECT â€" use "standard cores" for faster execution
result = PyOM.design_magnetics_from_converter(
"flyback", flyback, 3, "standard cores", True, None # faster!
)
# ⌠WRONG â€" abandoning Method A just because "available cores" is slow
# Don't do this: "it timed out, so I'll use Method B instead"Why this matters: Method A computes the optimal inductance, turns ratio, and operating waveforms automatically from the converter specification. Method B requires you to pre-calculate these values, which can introduce errors.
pip install PyOpenMagneticsIf the .whl is provided as base64-encoded parts:
import base64
with open("pyopenmagnetics-1.3.0.whl.base64.partaa", "rb") as f:
part_a = f.read()
with open("pyopenmagnetics-1.3.0.whl.base64.partab", "rb") as f:
part_b = f.read()
whl_data = base64.b64decode(part_a + part_b)
with open("pyopenmagnetics.whl", "wb") as f:
f.write(whl_data)
# Then: pip install pyopenmagnetics.whlThe package has no __init__.py. A bare import PyOpenMagnetics gives an
empty namespace with 0 functions. You MUST use importlib:
import importlib.util, os, glob
pkg_dir = os.path.join(
os.path.dirname(__import__('PyOpenMagnetics').__path__[0]),
'PyOpenMagnetics'
)
so_files = glob.glob(os.path.join(pkg_dir, 'PyOpenMagnetics.cpython-*'))
assert so_files, f"No .so/.pyd found in {pkg_dir}"
spec = importlib.util.spec_from_file_location('PyOpenMagnetics', so_files[0])
PyOM = importlib.util.module_from_spec(spec)
spec.loader.exec_module(PyOM)
# MANDATORY — must call before any other function
PyOM.load_databases({})Verify:
assert len(dir(PyOM)) > 100, "Module not loaded properly"
assert hasattr(PyOM, 'design_magnetics_from_converter')
print(f"Materials: {len(PyOM.get_core_material_names())}") # ~409
print(f"Shapes: {len(PyOM.get_core_shape_names(True))}") # ~1301This goes directly from converter specifications to complete, ranked magnetic component designs in a single call.
ngspice is shipped inside the wheel at .ngspice/lib/libngspice.so. No
separate install needed. The C++ code ignores the use_ngspice parameter:
(void)useNgspice; — it always uses ngspice internally.
In sandboxed environments where dlopen is restricted, ngspice may fail to
initialize — use Method B with use_ngspice=False in that case.
result = PyOM.design_magnetics_from_converter(
topology_name, # str — REQUIRED
converter_json, # dict — REQUIRED (BASE class schema, see Section 5)
max_results, # int — 1-10
core_mode_json, # str — "available cores" or "standard cores"
use_ngspice, # bool — IGNORED (always True internally)
weights_json # dict or None
).pyi says: topology=, converter=, core_mode=, weights=.
Actual pybind11: topology_name=, converter_json=, core_mode_json=, weights_json=.
Safest: use positional arguments.
The C++ pybind11 binding accepts Python dicts directly. json.dumps() turns
your dict into a string → the C++ parser gets a string instead of an object
→ "Input JSON does not conform to schema!".
# � WRONG — json.dumps() causes schema error
result = PyOM.design_magnetics_from_converter("flyback", json.dumps(converter), ...)
result = PyOM.design_magnetics_from_converter("flyback", converter, 3, json.dumps("STANDARD_CORES"), ...)
# ✅ CORRECT — pass Python dict and plain string
result = PyOM.design_magnetics_from_converter("flyback", converter, 3, "available cores", True, None)If design_magnetics_from_converter throws "Input JSON does not conform to schema!",
the fix is to correct the JSON — NOT to fall back to calculate_advised_cores or
manual math. Common fixes:
- Remove
json.dumps()from all arguments - Use
"available cores"(lowercase + space), not"STANDARD_CORES" - Use positional arguments, not keyword arguments
- For offline flyback: use the Advanced schema with
desiredInductance
From CoreAdviser.h from_json:
if (j == "available cores") x = CoreAdviserModes::AVAILABLE_CORES;
else if (j == "standard cores") x = CoreAdviserModes::STANDARD_CORES;
else if (j == "custom cores") x = CoreAdviserModes::CUSTOM_CORES;
else throw std::runtime_error("Input JSON does not conform to schema!");| � WRONG | ✅ CORRECT |
|---|---|
"AVAILABLE_CORES" |
"available cores" |
"STANDARD_CORES" |
"standard cores" |
"Available Cores" |
"available cores" |
0 (integer) |
"available cores" |
"available cores"— WE commercial cores (~1301 shapes, 60–120+ sec)"standard cores"— generic shapes (faster, fewer options)
The mode field is optional if currentRippleRatio is provided. The C++ code
will auto-infer the mode: CCM if ripple < 1.0, DCM if ripple >= 1.0.
If you omit both mode AND currentRippleRatio, you'll get an error:
"Either current ripple ratio or mode is needed for the Flyback OperatingPoint Mode"
Valid mode values:
"Continuous Conduction Mode"(CCM — most common for >20W)"Discontinuous Conduction Mode"(DCM)"Boundary Mode Operation"(BCM)"Quasi Resonant Mode"(QR)
Other topologies (Buck, Boost, Forward, LLC) do NOT need a mode field.
design_magnetics_from_converter() uses OpenMagnetics::Flyback (base).
process_converter() uses OpenMagnetics::AdvancedFlyback.
| Field | Method A (Base) | Method B (Advanced) |
|---|---|---|
desiredInductance |
� Causes schema error | ✅ Required |
desiredTurnsRatios |
� Causes schema error | ✅ Required |
desiredDutyCycle |
� Causes schema error | ✅ Optional |
currentRippleRatio |
✅ REQUIRED (Flyback/Boost/Forward) | ✅ Optional |
mode in operatingPoints |
Optional (auto-inferred if currentRippleRatio set) | Not needed |
flyback_base = {
"currentRippleRatio": 0.4, # REQUIRED (j.at)
"diodeVoltageDrop": 0.5, # REQUIRED (j.at)
"efficiency": 0.88, # REQUIRED (j.at)
"inputVoltage": { # REQUIRED (j.at)
"minimum": 185.0,
"nominal": 220.0, # recommended
"maximum": 265.0
},
"operatingPoints": [{ # REQUIRED (j.at)
"ambientTemperature": 25.0, # REQUIRED (j.at)
"outputVoltages": [12.0], # REQUIRED (j.at) — PLURAL
"outputCurrents": [2.0], # REQUIRED (j.at) — PLURAL
"switchingFrequency": 100000.0, # optional (get_stack_optional)
"mode": "Continuous Conduction Mode" # Optional if currentRippleRatio is set (auto-inferred)
}],
"maximumDutyCycle": 0.45, # optional
"maximumDrainSourceVoltage": 800.0 # optional
}flyback_advanced = {
"inputVoltage": {"minimum": 185, "maximum": 265},
"desiredInductance": 800e-6, # AdvancedFlyback only
"desiredTurnsRatios": [13.5], # AdvancedFlyback only
"desiredDutyCycle": [[0.45, 0.45]], # AdvancedFlyback only
"maximumDutyCycle": 0.45,
"efficiency": 0.88,
"diodeVoltageDrop": 0.5,
"currentRippleRatio": 0.4,
"operatingPoints": [{
"outputVoltages": [12.0],
"outputCurrents": [2.0],
"switchingFrequency": 100000,
"ambientTemperature": 25
}]
}buck_base = {
"diodeVoltageDrop": 0.5, # REQUIRED (j.at)
"inputVoltage": {"minimum": 10.0, "maximum": 14.0}, # REQUIRED
"operatingPoints": [{
"ambientTemperature": 25.0, # REQUIRED
"outputVoltage": 3.3, # REQUIRED — ⚠� SINGULAR!
"outputCurrent": 5.0, # REQUIRED — ⚠� SINGULAR!
"switchingFrequency": 500000.0 # REQUIRED (j.at)
}]
}boost_base = {
"currentRippleRatio": 0.3, # REQUIRED (j.at)
"diodeVoltageDrop": 0.7, # REQUIRED (j.at)
"efficiency": 0.92, # REQUIRED (j.at)
"inputVoltage": {"minimum": 5.0, "maximum": 5.0}, # REQUIRED
"operatingPoints": [{
"ambientTemperature": 25.0, # REQUIRED
"outputVoltage": 12.0, # REQUIRED — ⚠� SINGULAR!
"outputCurrent": 1.0, # REQUIRED — ⚠� SINGULAR!
"switchingFrequency": 100000.0 # REQUIRED (j.at)
}]
}forward_base = {
"currentRippleRatio": 0.4, # REQUIRED (j.at)
"diodeVoltageDrop": 0.5, # REQUIRED (j.at)
"inputVoltage": {"minimum": 36.0, "maximum": 72.0},
"operatingPoints": [{
"ambientTemperature": 25.0, # REQUIRED (j.at)
"outputVoltages": [5.0], # REQUIRED (j.at) — PLURAL
"outputCurrents": [10.0], # REQUIRED (j.at) — PLURAL
"switchingFrequency": 200000.0 # REQUIRED (j.at) for Forward!
}]
# optional: "efficiency", "dutyCycle", "maximumSwitchCurrent"
}Use topology strings: "single_switch_forward", "two_switch_forward", "active_clamp_forward".
llc_base = {
"inputVoltage": {"minimum": 380.0, "maximum": 420.0}, # REQUIRED (j.at)
"minSwitchingFrequency": 100000.0, # REQUIRED (j.at)
"maxSwitchingFrequency": 300000.0, # REQUIRED (j.at)
"operatingPoints": [{ # REQUIRED (j.at)
"ambientTemperature": 25.0,
"outputVoltages": [12.0], # REQUIRED — PLURAL
"outputCurrents": [5.0], # REQUIRED — PLURAL
"switchingFrequency": 200000.0 # Operating frequency
}],
# optional fields:
"efficiency": 0.95, # optional
"qualityFactor": 0.5, # optional
"resonantFrequency": 150000.0 # optional
}| Topology | outputVoltage(s) | outputCurrent(s) |
|---|---|---|
| Flyback | outputVoltages (PLURAL, list) |
outputCurrents (PLURAL, list) |
| Forward | outputVoltages (PLURAL, list) |
outputCurrents (PLURAL, list) |
| PushPull | outputVoltages (PLURAL, list) |
outputCurrents (PLURAL, list) |
| LLC | outputVoltages (PLURAL, list) |
outputCurrents (PLURAL, list) |
| Buck | outputVoltage (SINGULAR, float) |
outputCurrent (SINGULAR, float) |
| Boost | outputVoltage (SINGULAR, float) |
outputCurrent (SINGULAR, float) |
| DualActiveBridge | outputVoltage (SINGULAR) |
outputCurrent (SINGULAR) |
If user says "220V to 12V, 2A" without detail:
Vin_dc_min ≈ 185 × √2 × 0.9 ≈ 235V
Dmax = 0.45, η = 0.88
n = (12+0.5)×0.55 / (235×0.45×0.88) ≈ 0.074
turnsRatio = 1/n ≈ 13.5 → for desiredTurnsRatios (Method B only)
Lm ≈ 800 µH → for desiredInductance (Method B only)
import importlib.util, os, glob, json
# Load module
pkg_dir = os.path.join(
os.path.dirname(__import__('PyOpenMagnetics').__path__[0]),
'PyOpenMagnetics'
)
so_files = glob.glob(os.path.join(pkg_dir, 'PyOpenMagnetics.cpython-*'))
spec = importlib.util.spec_from_file_location('PyOpenMagnetics', so_files[0])
PyOM = importlib.util.module_from_spec(spec)
spec.loader.exec_module(PyOM)
PyOM.load_databases({})
# Define converter (BASE Flyback schema — NO desiredInductance!)
flyback = {
"currentRippleRatio": 0.4,
"diodeVoltageDrop": 0.5,
"efficiency": 0.88,
"inputVoltage": {"minimum": 185.0, "nominal": 220.0, "maximum": 265.0},
"maximumDutyCycle": 0.45,
"operatingPoints": [{
"ambientTemperature": 25.0,
"outputVoltages": [12.0],
"outputCurrents": [2.0],
"switchingFrequency": 100000.0,
"mode": "Continuous Conduction Mode" # Optional if currentRippleRatio is set (auto-inferred)
}]
}
# Design (takes 60-120s with "available cores")
result = PyOM.design_magnetics_from_converter(
"flyback", flyback, 1, "available cores", True, None
)
if isinstance(result, dict) and "error" in result:
print(f"Method A failed: {result['error']}")
# → Use Method B
else:
d = result[0]
mas_obj, score = (d[0], d[1]) if isinstance(d, (list, tuple)) else (d, "N/A")
core = mas_obj["magnetic"]["core"]["functionalDescription"]
coil = mas_obj["magnetic"]["coil"]["functionalDescription"]
print(f"Core: {core['shape'].get('name','?') if isinstance(core['shape'], dict) else core['shape']}")
print(f"Material: {core['material'].get('name','?') if isinstance(core['material'], dict) else core['material']}")
for w in coil:
print(f" {w.get('name','?')}: {w.get('numberTurns','?')} turns")# Step 1: Process converter (AdvancedFlyback schema)
flyback_adv = {
"inputVoltage": {"minimum": 185, "maximum": 265},
"desiredInductance": 800e-6,
"desiredTurnsRatios": [13.5],
"desiredDutyCycle": [[0.45, 0.45]],
"maximumDutyCycle": 0.45,
"efficiency": 0.88,
"diodeVoltageDrop": 0.5,
"currentRippleRatio": 0.4,
"operatingPoints": [{
"outputVoltages": [12.0],
"outputCurrents": [2.0],
"switchingFrequency": 100000,
"ambientTemperature": 25
}]
}
processed = PyOM.process_converter("flyback", flyback_adv, use_ngspice=False)
assert "error" not in processed
# Step 2: Feed into adviser (with optional weights)
mas_inputs = {
"designRequirements": processed["designRequirements"],
"operatingPoints": processed["operatingPoints"]
}
designs = PyOM.calculate_advised_magnetics(
mas_inputs, 1, "available cores",
{"efficiency": 2.0, "cost": 1.0, "dimensions": 0.5} # optional weights
)
# Step 3: Parse
d = designs[0]
mas_obj, score = (d[0], d[1]) if isinstance(d, (list, tuple)) else (d, "N/A")
core = mas_obj["magnetic"]["core"]["functionalDescription"]
coil = mas_obj["magnetic"]["coil"]["functionalDescription"]
print(f"Core: {core['shape'].get('name','?')}, Material: {core['material'].get('name','?')}")
for w in coil:
print(f" {w['name']}: {w['numberTurns']} turns, {w.get('numberParallels',1)} parallels")Both design_magnetics_from_converter() and calculate_advised_magnetics() accept
an optional weights dict. The keys must be lowercase MagneticFilters enum values:
weights = {
"efficiency": 2.0, # prioritize low losses
"cost": 1.0, # consider cost
"dimensions": 0.5 # size is less important
}Valid weight keys (from MAS.hpp MagneticFilters from_json):
"cost"— minimize core/wire cost"dimensions"— minimize physical size"efficiency"— minimize total losses
Pass as the 4th argument to calculate_advised_magnetics() or 6th to
design_magnetics_from_converter(). Pass None for default equal weights.
Control global behavior with the settings API:
# Get current settings
settings = PyOM.get_settings()
# Modify settings
PyOM.set_settings({
"useOnlyCoresInStock": True, # only use cores marked in stock
"painterNumberPointsX": 100, # plot X resolution
"painterNumberPointsY": 100, # plot Y resolution
"coilAllowMarginTape": True, # allow margin tape in coil designs
"coilAllowInsulatedWire": True, # allow insulated wire
"magneticFieldMirroringDimension": 0 # simulation accuracy (0=fast, higher=more accurate)
})
# Reset to defaults
PyOM.reset_settings()⚠� Naming convention: single-item lookup functions use the
find_*_by_name()prefix, NOTget_*_by_name().get_core_shape_by_name()does not exist and will raiseAttributeError.
names = PyOM.get_core_shape_names(True) # ✅ verified — True=include toroidal
families = PyOM.get_core_shape_families() # ✅ verified — NO argument (bool arg → TypeError)
shape = PyOM.find_core_shape_by_name("E 25/13/7") # ✅ verifiedmat_names = PyOM.get_core_material_names() # ✅ verified
material = PyOM.find_core_material_by_name("3C95") # ✅ verified (.pyi confirmed)wire_names = PyOM.get_wire_names() # ✅ verified
wire = PyOM.find_wire_by_name("Round 0.5 - Grade 1") # ✅ verified (.pyi confirmed)bobbin = PyOM.find_bobbin_by_name("E 25/13/7") # ✅ verified (.pyi confirmed)PyOM.get_core_shape_by_name(...) # AttributeError — does not exist
PyOM.get_core_material_by_name(...) # AttributeError — does not exist
PyOM.get_wire_by_name(...) # AttributeError — does not exist
PyOM.get_bobbin_by_name(...) # AttributeError — does not exist
PyOM.get_core_shape_families(True) # TypeError — takes no argumentsinductance = PyOM.calculate_inductance(magnetic)
# Returns dict with:
# magnetizingInductance → {magnetizingInductance, coreReluctance, gappingReluctance, ...}models = {"coreLosses": "IGSE"} # or "STEINMETZ", "ROSHEN", etc.
losses = PyOM.calculate_core_losses(core, coil, operating_point, models)winding_losses = PyOM.calculate_winding_losses(magnetic, operating_point, temperature)sim_result = PyOM.simulate(mas)# Skin depth at frequency
delta = PyOM.calculate_effective_skin_depth("copper", 100000, 25)
# DC resistance per meter for a given wire diameter
rdc = PyOM.calculate_dc_resistance_per_meter("copper", 0.5e-3, 25)subcircuit = PyOM.export_magnetic_as_subcircuit(magnetic)
# Returns SPICE subcircuit string| Topology string | Method A class | Singular/Plural | Notes |
|---|---|---|---|
"flyback" |
Flyback |
PLURAL + mode required | Most common |
"buck" |
Buck |
SINGULAR | |
"boost" |
Boost |
SINGULAR | |
"single_switch_forward" |
SingleSwitchForward |
PLURAL | switchingFreq REQUIRED |
"two_switch_forward" |
TwoSwitchForward |
PLURAL | switchingFreq REQUIRED |
"active_clamp_forward" |
ActiveClampForward |
PLURAL | switchingFreq REQUIRED |
"push_pull" |
PushPull |
PLURAL | Same as Forward |
"llc" |
Llc |
PLURAL | |
"isolated_buck" |
IsolatedBuck |
PLURAL | |
"isolated_buck_boost" |
IsolatedBuckBoost |
PLURAL | |
Others ("cllc", "dab", "psfb", "pshb") |
internal fallback | varies |
Per-topology thin wrappers for process_converter:
process_flyback(), process_buck(), process_boost(),
process_single_switch_forward(), process_two_switch_forward(),
process_active_clamp_forward(), process_push_pull(),
process_isolated_buck(), process_isolated_buck_boost(),
process_current_transformer(json, turns_ratio, secondary_resistance=0.0)
Both methods return a list of [mas_dict, score] tuples:
d = result[0] # First (best) design
mas_obj = d[0] # MAS dict
score = d[1] # float — higher is better
# Core info
core_fd = mas_obj["magnetic"]["core"]["functionalDescription"]
shape = core_fd["shape"] # dict with "name", dimensions, etc.
material = core_fd["material"] # dict with "name", properties, etc.
gapping = core_fd["gapping"] # list of gap dicts
# Coil info
coil_fd = mas_obj["magnetic"]["coil"]["functionalDescription"]
for winding in coil_fd:
name = winding["name"] # "primary", "secondary", etc.
turns = winding["numberTurns"] # int
parallels = winding.get("numberParallels", 1)
wire = winding.get("wire", {}) # wire specification
# Design requirements used
dr = mas_obj["inputs"]["designRequirements"]
mag_ind = dr["magnetizingInductance"] # {nominal, minimum, maximum}
turns_ratios = dr["turnsRatios"] # list of ratios
# Operating points used (with full waveforms)
ops = mas_obj["inputs"]["operatingPoints"]| Error | Cause | Fix |
|---|---|---|
"Input JSON does not conform to schema!" (instant) |
Used json.dumps() on converter or core_mode |
Pass Python dict directly — NOT json.dumps(dict) |
"Input JSON does not conform to schema!" (instant) |
Wrong core_mode_json |
Use "available cores" (lowercase + space!) |
"Input JSON does not conform to schema!" (instant) |
Missing both mode and currentRippleRatio |
Add either mode OR currentRippleRatio (mode auto-inferred if ripple set) |
"Input JSON does not conform to schema!" (instant) |
Used desiredInductance with Method A |
Remove it — base class doesn't accept it |
"ngspice is not available" |
Sandbox restriction | Use Method B with use_ngspice=False |
"key 'currentRippleRatio' not found" |
Missing required field | Add to JSON |
"key 'outputVoltage' not found" |
Used plural for Buck/Boost | Use singular: outputVoltage, outputCurrent |
"key 'outputVoltages' not found" |
Used singular for Flyback/Forward | Use plural: outputVoltages, outputCurrents |
TypeError: incompatible function arguments |
Wrong keyword names | Use positional args |
| Empty namespace (0 functions) | Bare import PyOpenMagnetics |
Use importlib (Section 2) |
get_core_shape_names() TypeError |
Missing bool arg | Use get_core_shape_names(True) |
❌ WRONG: Using json.dumps()
# This WILL FAIL with "Input JSON does not conform to schema!"
result = PyOM.design_magnetics_from_converter(
"flyback",
json.dumps(converter_spec), # ❌ WRONG - json.dumps() converts dict to string!
3
)✅ CORRECT: Pass Python dict directly
# This works - pass the dict directly, no json.dumps()
result = PyOM.design_magnetics_from_converter(
"flyback",
converter_spec, # ✅ CORRECT - Python dict, not string
3,
"standard cores",
True,
None
)❌ WRONG: Inventing your own JSON structure
# This WILL FAIL - this is NOT the correct schema!
converter_spec = {
"inputs": [{
"name": "Primary",
"voltage": {"nominal": 310.0}
}],
"outputs": [{
"name": "Secondary",
"voltage": 12.0,
"current": 2.0
}],
"switchingFrequency": 100000.0
}✅ CORRECT: Use the exact schema from Section 5.1
# This is the CORRECT Flyback schema for Method A
flyback = {
"currentRippleRatio": 0.4, # REQUIRED
"diodeVoltageDrop": 0.5, # REQUIRED
"efficiency": 0.88, # REQUIRED
"inputVoltage": { # REQUIRED - not "inputs"!
"minimum": 185.0,
"nominal": 220.0,
"maximum": 265.0
},
"operatingPoints": [{ # REQUIRED - not "outputs"!
"ambientTemperature": 25.0,
"outputVoltages": [12.0], # PLURAL - list!
"outputCurrents": [2.0], # PLURAL - list!
"switchingFrequency": 100000.0
}],
"maximumDutyCycle": 0.45
}❌ WRONG: Using keyword arguments from .pyi stubs
# This WILL FAIL - .pyi has wrong keyword names!
result = PyOM.design_magnetics_from_converter(
topology="flyback", # ❌ Wrong keyword
converter=flyback, # ❌ Wrong keyword
max_results=3
)✅ CORRECT: Use positional arguments
# Use positional arguments - they always work
result = PyOM.design_magnetics_from_converter(
"flyback", # topology_name (positional)
flyback, # converter_json (positional)
3, # max_results (positional)
"standard cores", # core_mode_json (positional)
True, # use_ngspice (positional, ignored internally)
None # weights_json (positional)
)❌ WRONG: Abandoning Method A after schema error
# DON'T DO THIS!
try:
result = PyOM.design_magnetics_from_converter(...)
except:
print("Method A failed, doing manual calculations instead...")
# ❌ WRONG - Never fall back to manual calculations!
L = V * D / (f * delta_I) # ❌ NO!✅ CORRECT: Fix the JSON and retry
# If you get a schema error, FIX THE JSON, don't abandon Method A
# Check:
# 1. Did you use json.dumps()? Remove it.
# 2. Did you use the correct field names? Check Section 5.
# 3. Did you use "available cores" (lowercase with space)?
# 4. Did you include all REQUIRED fields?- Used
importlibto load.so(NOT bareimport) - Called
load_databases({})after loading - Topology is lowercase (
"flyback", not"Flyback") -
core_mode_jsonis"available cores"(lowercase + space!) - JSON uses BASE class schema (NO
desiredInductance, NOdesiredTurnsRatios) - For Flyback:
currentRippleRatiopresent (mode is optional, auto-inferred) - For Buck/Boost:
outputVoltage/outputCurrentare SINGULAR - For Forward:
switchingFrequencyis REQUIRED in operatingPoints - Using positional arguments (keyword names in .pyi are wrong)
- Passing Python dicts directly — NOT
json.dumps()(causes schema error) - If error → fix JSON and retry, then Method B — NEVER manual calculations
- JSON uses Advanced schema (WITH
desiredInductance,desiredTurnsRatios) -
use_ngspice=Falseif ngspice can't init,Trueotherwise - Pass
processed["designRequirements"]+processed["operatingPoints"]to adviser - Core mode also uses
"available cores"(same lowercase convention) - Weights use lowercase:
"efficiency","cost","dimensions"
-
use_ngspiceis ignored bydesign_magnetics_from_converter—(void)useNgspice;in source. ngspice is bundled in the wheel. In restricted sandboxes, use Method B. -
.pyihas wrong keyword names — use positional args ortopology_name=,converter_json=,core_mode_json=,weights_json=. -
Two different Flyback classes —
Flyback(base, Method A) vsAdvancedFlyback(Method B). Different JSON schemas. Never mix them. -
get_core_shape_names()requires boolean arg:True=include toroidal. -
Design computation is CPU-intensive —
"available cores"searches 1301+ shapes (60–180+ sec). Use"standard cores"for speed (10–30 sec). A timeout is NOT a failure — use "standard cores" or increase timeout, do NOT switch to Method B. -
All enum string values are lowercase —
"available cores","standard cores","efficiency","cost","dimensions", etc. The only exception isFlybackModeswhich uses Title Case:"Continuous Conduction Mode". -
process_converterreturns two keys —designRequirements(withmagnetizingInductance,turnsRatios,name,topology) andoperatingPoints(with full excitation waveforms per winding). -
Do NOT
json.dumps()the arguments — the pybind11 binding accepts Python dicts directly.json.dumps(converter)turns the dict into a string, which the C++ JSON parser rejects with a schema error. -
NEVER abandon Method A after a schema error — the error means your JSON is wrong, not that the function is broken. Fix the JSON and retry. Do NOT fall back to
calculate_advised_coresor manual textbook formulas.