PyOpenMagnetics 1.4.5__tar.gz → 1.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/PKG-INFO +1 -1
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/PyOpenMagnetics.pyi +16 -5
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/llms.txt +4 -2
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/pyproject.toml +1 -1
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/converter.cpp +248 -88
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/converter.h +7 -6
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/core.cpp +48 -4
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/core.h +2 -1
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/.github/workflows/ci.yml +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/.github/workflows/publish.yml +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/.gitignore +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/AGENTS.md +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/CMakeLists.txt +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/LICENSE +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/README.md +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/__init__.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/api/MAS.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/api/mas_db_reader.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/api/validation.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/clear_cibuildwheel_cache.sh +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/docs/compatibility.md +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/docs/errors.md +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/docs/performance.md +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/README.md +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/buck_inductor.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/complete_simulation_example.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/converter_design_example.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/debug_bobbin.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/debug_coil.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/debug_core.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/debug_plotting.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/flyback_220v_12v_1a.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/flyback_220v_12v_2a_complete.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/flyback_bh_curve.png +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/flyback_core.png +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/flyback_design.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/flyback_summary.png +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/flyback_waveforms.png +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/list_plot_funcs.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/plot_flyback_design.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/plot_flyback_pyom.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/test_field_calc.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/examples/test_field_plot.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/force_fresh_build.sh +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/notebooks/01_getting_started.ipynb +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/notebooks/02_buck_inductor.ipynb +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/notebooks/03_core_losses.ipynb +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/notebooks/README.md +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/requirements.txt +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/advisers.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/advisers.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/bobbin.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/bobbin.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/common.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/database.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/database.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/logging.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/logging.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/losses.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/losses.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/module.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/plotting.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/plotting.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/settings.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/settings.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/simulation.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/simulation.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/utils.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/utils.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/winding.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/winding.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/wire.cpp +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/src/wire.h +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/test.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/__init__.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/conftest.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/test_converter_endpoints.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/test_core.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/test_core_adviser.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/test_examples_integration.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/test_inputs.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/test_logging.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/test_magnetic_adviser.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/test_plotting.py +0 -0
- {pyopenmagnetics-1.4.5 → pyopenmagnetics-1.5.0}/tests/test_winding.py +0 -0
|
@@ -84,7 +84,7 @@ by reading AGENTS.md before starting.
|
|
|
84
84
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
85
85
|
"""
|
|
86
86
|
|
|
87
|
-
from typing import Dict, List, Any, Optional, Union, Literal
|
|
87
|
+
from typing import Dict, List, Any, Optional, Union, Literal, overload
|
|
88
88
|
|
|
89
89
|
# Type aliases for JSON-like structures
|
|
90
90
|
JsonDict = Dict[str, Any]
|
|
@@ -373,12 +373,23 @@ def calculate_inductance_from_number_turns_and_gapping(
|
|
|
373
373
|
"""
|
|
374
374
|
...
|
|
375
375
|
|
|
376
|
+
@overload
|
|
376
377
|
def calculate_number_turns_from_gapping_and_inductance(
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
378
|
+
core_data: Core,
|
|
379
|
+
coil_data: Coil,
|
|
380
|
+
inputs_data: Inputs,
|
|
381
|
+
models_data: ModelsDict
|
|
382
|
+
) -> int:
|
|
383
|
+
"""Calculate required turns for target inductance with given gap (coil-aware, preferred)."""
|
|
384
|
+
...
|
|
385
|
+
|
|
386
|
+
@overload
|
|
387
|
+
def calculate_number_turns_from_gapping_and_inductance(
|
|
388
|
+
core_data: Core,
|
|
389
|
+
inputs_data: Inputs,
|
|
390
|
+
models_data: ModelsDict
|
|
380
391
|
) -> int:
|
|
381
|
-
"""
|
|
392
|
+
"""Legacy 3-argument form (no coil_data); synthesizes a single-primary-winding coil. Prefer the coil-aware overload."""
|
|
382
393
|
...
|
|
383
394
|
|
|
384
395
|
def calculate_gapping_from_number_turns_and_inductance(
|
|
@@ -230,10 +230,12 @@ L = PyOpenMagnetics.calculate_inductance_from_number_turns_and_gapping(
|
|
|
230
230
|
core, coil, operating_point, models
|
|
231
231
|
)
|
|
232
232
|
|
|
233
|
-
# Calculate turns from inductance and gap
|
|
233
|
+
# Calculate turns from inductance and gap (coil-aware, preferred)
|
|
234
234
|
N = PyOpenMagnetics.calculate_number_turns_from_gapping_and_inductance(
|
|
235
|
-
core, inputs, models
|
|
235
|
+
core, coil, inputs, models
|
|
236
236
|
)
|
|
237
|
+
# Legacy 3-argument form (no coil) is still accepted for backward compatibility:
|
|
238
|
+
# N = PyOpenMagnetics.calculate_number_turns_from_gapping_and_inductance(core, inputs, models)
|
|
237
239
|
|
|
238
240
|
# Calculate gap from turns and inductance
|
|
239
241
|
core_with_gap = PyOpenMagnetics.calculate_gapping_from_number_turns_and_inductance(
|
|
@@ -149,7 +149,75 @@ static std::string normalize_topology_name(const std::string& s) {
|
|
|
149
149
|
return s;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
153
|
+
// Base-spec fast path (ABT #11)
|
|
154
|
+
//
|
|
155
|
+
// The fast path normally constructs an Advanced* converter whose from_json
|
|
156
|
+
// hard-requires `desiredInductance` (e.g. AdvancedBuck, MKF Buck.h:219). A
|
|
157
|
+
// caller passing a BASE spec (operating point + currentRippleRatio, no
|
|
158
|
+
// desiredInductance) would otherwise get
|
|
159
|
+
// `[json.exception.out_of_range.403] key 'desiredInductance' not found`.
|
|
160
|
+
//
|
|
161
|
+
// When `desiredInductance` is absent we instead construct the BASE converter
|
|
162
|
+
// class, whose virtual process_design_requirements() DERIVES the inductance
|
|
163
|
+
// from the operating points + currentRippleRatio (or maximumSwitchCurrent) —
|
|
164
|
+
// the same MKF math the slow path uses. No L-derivation is duplicated here;
|
|
165
|
+
// it all stays in MKF (house rule). If neither desiredInductance nor a ripple
|
|
166
|
+
// driver is present, the base class throws a loud, specific exception rather
|
|
167
|
+
// than substituting a default.
|
|
168
|
+
//
|
|
169
|
+
// Two helpers cover the two simulate signatures: single-inductor topologies
|
|
170
|
+
// (Buck/Boost/Cuk/…) take a scalar inductance; transformer topologies
|
|
171
|
+
// (Flyback/Forward family/IsolatedBuck/…) take (turnsRatios, inductance).
|
|
172
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
173
|
+
template <typename BaseConverter>
|
|
174
|
+
OpenMagnetics::Inputs process_base_spec_scalar_L(const json& converterJson, bool useNgspice, MAS::Topologies topology) {
|
|
175
|
+
BaseConverter converter(converterJson);
|
|
176
|
+
converter._assertErrors = true;
|
|
177
|
+
if (useNgspice) {
|
|
178
|
+
auto designReqs = converter.process_design_requirements();
|
|
179
|
+
double inductance = OpenMagnetics::resolve_dimensional_values(designReqs.get_magnetizing_inductance());
|
|
180
|
+
auto operatingPoints = converter.simulate_and_extract_operating_points(inductance);
|
|
181
|
+
OpenMagnetics::Inputs result;
|
|
182
|
+
result.set_design_requirements(designReqs);
|
|
183
|
+
result.set_operating_points(operatingPoints);
|
|
184
|
+
result.get_mutable_design_requirements().set_topology(topology);
|
|
185
|
+
return result;
|
|
186
|
+
} else {
|
|
187
|
+
OpenMagnetics::Inputs result = converter.process();
|
|
188
|
+
result.get_mutable_design_requirements().set_topology(topology);
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
template <typename BaseConverter>
|
|
194
|
+
OpenMagnetics::Inputs process_base_spec_vector_L(const json& converterJson, bool useNgspice, MAS::Topologies topology) {
|
|
195
|
+
BaseConverter converter(converterJson);
|
|
196
|
+
converter._assertErrors = true;
|
|
197
|
+
if (useNgspice) {
|
|
198
|
+
auto designReqs = converter.process_design_requirements();
|
|
199
|
+
std::vector<double> turnsRatios;
|
|
200
|
+
for (const auto& tr : designReqs.get_turns_ratios()) {
|
|
201
|
+
turnsRatios.push_back(OpenMagnetics::resolve_dimensional_values(tr));
|
|
202
|
+
}
|
|
203
|
+
double inductance = OpenMagnetics::resolve_dimensional_values(designReqs.get_magnetizing_inductance());
|
|
204
|
+
auto operatingPoints = converter.simulate_and_extract_operating_points(turnsRatios, inductance);
|
|
205
|
+
OpenMagnetics::Inputs result;
|
|
206
|
+
result.set_design_requirements(designReqs);
|
|
207
|
+
result.set_operating_points(operatingPoints);
|
|
208
|
+
result.get_mutable_design_requirements().set_topology(topology);
|
|
209
|
+
return result;
|
|
210
|
+
} else {
|
|
211
|
+
OpenMagnetics::Inputs result = converter.process();
|
|
212
|
+
result.get_mutable_design_requirements().set_topology(topology);
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
152
217
|
OpenMagnetics::Inputs process_flyback_internal(const json& converterJson, bool useNgspice) {
|
|
218
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
219
|
+
return process_base_spec_vector_L<OpenMagnetics::Flyback>(converterJson, useNgspice, MAS::Topologies::FLYBACK_CONVERTER);
|
|
220
|
+
}
|
|
153
221
|
OpenMagnetics::AdvancedFlyback converter(converterJson);
|
|
154
222
|
converter._assertErrors = true;
|
|
155
223
|
|
|
@@ -184,6 +252,9 @@ OpenMagnetics::Inputs process_flyback_internal(const json& converterJson, bool u
|
|
|
184
252
|
}
|
|
185
253
|
|
|
186
254
|
OpenMagnetics::Inputs process_buck_internal(const json& converterJson, bool useNgspice) {
|
|
255
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
256
|
+
return process_base_spec_scalar_L<OpenMagnetics::Buck>(converterJson, useNgspice, MAS::Topologies::BUCK_CONVERTER);
|
|
257
|
+
}
|
|
187
258
|
OpenMagnetics::AdvancedBuck converter(converterJson);
|
|
188
259
|
converter._assertErrors = true;
|
|
189
260
|
|
|
@@ -204,6 +275,9 @@ OpenMagnetics::Inputs process_buck_internal(const json& converterJson, bool useN
|
|
|
204
275
|
}
|
|
205
276
|
|
|
206
277
|
OpenMagnetics::Inputs process_boost_internal(const json& converterJson, bool useNgspice) {
|
|
278
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
279
|
+
return process_base_spec_scalar_L<OpenMagnetics::Boost>(converterJson, useNgspice, MAS::Topologies::BOOST_CONVERTER);
|
|
280
|
+
}
|
|
207
281
|
OpenMagnetics::AdvancedBoost converter(converterJson);
|
|
208
282
|
converter._assertErrors = true;
|
|
209
283
|
|
|
@@ -224,6 +298,9 @@ OpenMagnetics::Inputs process_boost_internal(const json& converterJson, bool use
|
|
|
224
298
|
}
|
|
225
299
|
|
|
226
300
|
OpenMagnetics::Inputs process_single_switch_forward_internal(const json& converterJson, bool useNgspice) {
|
|
301
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
302
|
+
return process_base_spec_vector_L<OpenMagnetics::SingleSwitchForward>(converterJson, useNgspice, MAS::Topologies::SINGLE_SWITCH_FORWARD_CONVERTER);
|
|
303
|
+
}
|
|
227
304
|
OpenMagnetics::AdvancedSingleSwitchForward converter(converterJson);
|
|
228
305
|
converter._assertErrors = true;
|
|
229
306
|
|
|
@@ -248,6 +325,9 @@ OpenMagnetics::Inputs process_single_switch_forward_internal(const json& convert
|
|
|
248
325
|
}
|
|
249
326
|
|
|
250
327
|
OpenMagnetics::Inputs process_two_switch_forward_internal(const json& converterJson, bool useNgspice) {
|
|
328
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
329
|
+
return process_base_spec_vector_L<OpenMagnetics::TwoSwitchForward>(converterJson, useNgspice, MAS::Topologies::TWO_SWITCH_FORWARD_CONVERTER);
|
|
330
|
+
}
|
|
251
331
|
OpenMagnetics::AdvancedTwoSwitchForward converter(converterJson);
|
|
252
332
|
converter._assertErrors = true;
|
|
253
333
|
|
|
@@ -272,6 +352,9 @@ OpenMagnetics::Inputs process_two_switch_forward_internal(const json& converterJ
|
|
|
272
352
|
}
|
|
273
353
|
|
|
274
354
|
OpenMagnetics::Inputs process_active_clamp_forward_internal(const json& converterJson, bool useNgspice) {
|
|
355
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
356
|
+
return process_base_spec_vector_L<OpenMagnetics::ActiveClampForward>(converterJson, useNgspice, MAS::Topologies::ACTIVE_CLAMP_FORWARD_CONVERTER);
|
|
357
|
+
}
|
|
275
358
|
OpenMagnetics::AdvancedActiveClampForward converter(converterJson);
|
|
276
359
|
converter._assertErrors = true;
|
|
277
360
|
|
|
@@ -296,6 +379,9 @@ OpenMagnetics::Inputs process_active_clamp_forward_internal(const json& converte
|
|
|
296
379
|
}
|
|
297
380
|
|
|
298
381
|
OpenMagnetics::Inputs process_push_pull_internal(const json& converterJson, bool useNgspice) {
|
|
382
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
383
|
+
return process_base_spec_vector_L<OpenMagnetics::PushPull>(converterJson, useNgspice, MAS::Topologies::PUSH_PULL_CONVERTER);
|
|
384
|
+
}
|
|
299
385
|
OpenMagnetics::AdvancedPushPull converter(converterJson);
|
|
300
386
|
converter._assertErrors = true;
|
|
301
387
|
|
|
@@ -428,6 +514,9 @@ OpenMagnetics::Inputs process_pshb_internal(const json& converterJson, bool useN
|
|
|
428
514
|
}
|
|
429
515
|
|
|
430
516
|
OpenMagnetics::Inputs process_isolated_buck_internal(const json& converterJson, bool useNgspice) {
|
|
517
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
518
|
+
return process_base_spec_vector_L<OpenMagnetics::IsolatedBuck>(converterJson, useNgspice, MAS::Topologies::ISOLATED_BUCK_CONVERTER);
|
|
519
|
+
}
|
|
431
520
|
OpenMagnetics::AdvancedIsolatedBuck converter(converterJson);
|
|
432
521
|
converter._assertErrors = true;
|
|
433
522
|
|
|
@@ -452,6 +541,9 @@ OpenMagnetics::Inputs process_isolated_buck_internal(const json& converterJson,
|
|
|
452
541
|
}
|
|
453
542
|
|
|
454
543
|
OpenMagnetics::Inputs process_isolated_buck_boost_internal(const json& converterJson, bool useNgspice) {
|
|
544
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
545
|
+
return process_base_spec_vector_L<OpenMagnetics::IsolatedBuckBoost>(converterJson, useNgspice, MAS::Topologies::ISOLATED_BUCK_BOOST_CONVERTER);
|
|
546
|
+
}
|
|
455
547
|
OpenMagnetics::AdvancedIsolatedBuckBoost converter(converterJson);
|
|
456
548
|
converter._assertErrors = true;
|
|
457
549
|
|
|
@@ -511,6 +603,9 @@ OpenMagnetics::Inputs process_pfc_internal(const json& converterJson) {
|
|
|
511
603
|
// ─────────────────────────────────────────────────────────────────────
|
|
512
604
|
|
|
513
605
|
OpenMagnetics::Inputs process_cuk_internal(const json& converterJson, bool useNgspice) {
|
|
606
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
607
|
+
return process_base_spec_scalar_L<OpenMagnetics::Cuk>(converterJson, useNgspice, MAS::Topologies::CUK_CONVERTER);
|
|
608
|
+
}
|
|
514
609
|
OpenMagnetics::AdvancedCuk converter(converterJson);
|
|
515
610
|
converter._assertErrors = true;
|
|
516
611
|
if (useNgspice) {
|
|
@@ -530,6 +625,9 @@ OpenMagnetics::Inputs process_cuk_internal(const json& converterJson, bool useNg
|
|
|
530
625
|
}
|
|
531
626
|
|
|
532
627
|
OpenMagnetics::Inputs process_sepic_internal(const json& converterJson, bool useNgspice) {
|
|
628
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
629
|
+
return process_base_spec_scalar_L<OpenMagnetics::Sepic>(converterJson, useNgspice, MAS::Topologies::SEPIC_CONVERTER);
|
|
630
|
+
}
|
|
533
631
|
OpenMagnetics::AdvancedSepic converter(converterJson);
|
|
534
632
|
converter._assertErrors = true;
|
|
535
633
|
if (useNgspice) {
|
|
@@ -549,6 +647,9 @@ OpenMagnetics::Inputs process_sepic_internal(const json& converterJson, bool use
|
|
|
549
647
|
}
|
|
550
648
|
|
|
551
649
|
OpenMagnetics::Inputs process_zeta_internal(const json& converterJson, bool useNgspice) {
|
|
650
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
651
|
+
return process_base_spec_scalar_L<OpenMagnetics::Zeta>(converterJson, useNgspice, MAS::Topologies::ZETA_CONVERTER);
|
|
652
|
+
}
|
|
552
653
|
OpenMagnetics::AdvancedZeta converter(converterJson);
|
|
553
654
|
converter._assertErrors = true;
|
|
554
655
|
if (useNgspice) {
|
|
@@ -568,6 +669,9 @@ OpenMagnetics::Inputs process_zeta_internal(const json& converterJson, bool useN
|
|
|
568
669
|
}
|
|
569
670
|
|
|
570
671
|
OpenMagnetics::Inputs process_four_switch_buck_boost_internal(const json& converterJson, bool useNgspice) {
|
|
672
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
673
|
+
return process_base_spec_scalar_L<OpenMagnetics::FourSwitchBuckBoost>(converterJson, useNgspice, MAS::Topologies::FOUR_SWITCH_BUCK_BOOST_CONVERTER);
|
|
674
|
+
}
|
|
571
675
|
OpenMagnetics::AdvancedFourSwitchBuckBoost converter(converterJson);
|
|
572
676
|
converter._assertErrors = true;
|
|
573
677
|
if (useNgspice) {
|
|
@@ -610,6 +714,35 @@ OpenMagnetics::Inputs process_asymmetric_half_bridge_internal(const json& conver
|
|
|
610
714
|
}
|
|
611
715
|
|
|
612
716
|
OpenMagnetics::Inputs process_weinberg_internal(const json& converterJson, bool useNgspice) {
|
|
717
|
+
// Base-spec fast path (ABT #11): derive L from the base Weinberg when no
|
|
718
|
+
// desiredInductance is supplied. Inlined (not via the shared helper)
|
|
719
|
+
// because Weinberg's simulate signature takes a SCALAR turns ratio
|
|
720
|
+
// (single-secondary topology), not the vector the other transformers use.
|
|
721
|
+
if (!converterJson.contains("desiredInductance")) {
|
|
722
|
+
OpenMagnetics::Weinberg converter(converterJson);
|
|
723
|
+
converter._assertErrors = true;
|
|
724
|
+
if (useNgspice) {
|
|
725
|
+
auto designReqs = converter.process_design_requirements();
|
|
726
|
+
std::vector<double> turnsRatios;
|
|
727
|
+
for (const auto& tr : designReqs.get_turns_ratios()) {
|
|
728
|
+
turnsRatios.push_back(OpenMagnetics::resolve_dimensional_values(tr));
|
|
729
|
+
}
|
|
730
|
+
if (turnsRatios.empty()) {
|
|
731
|
+
throw std::runtime_error("Weinberg converter requires at least one turns ratio");
|
|
732
|
+
}
|
|
733
|
+
double inductance = OpenMagnetics::resolve_dimensional_values(designReqs.get_magnetizing_inductance());
|
|
734
|
+
auto operatingPoints = converter.simulate_and_extract_operating_points(turnsRatios[0], inductance);
|
|
735
|
+
OpenMagnetics::Inputs result;
|
|
736
|
+
result.set_design_requirements(designReqs);
|
|
737
|
+
result.set_operating_points(operatingPoints);
|
|
738
|
+
result.get_mutable_design_requirements().set_topology(MAS::Topologies::WEINBERG_CONVERTER);
|
|
739
|
+
return result;
|
|
740
|
+
} else {
|
|
741
|
+
OpenMagnetics::Inputs result = converter.process();
|
|
742
|
+
result.get_mutable_design_requirements().set_topology(MAS::Topologies::WEINBERG_CONVERTER);
|
|
743
|
+
return result;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
613
746
|
OpenMagnetics::AdvancedWeinberg converter(converterJson);
|
|
614
747
|
converter._assertErrors = true;
|
|
615
748
|
if (useNgspice) {
|
|
@@ -788,16 +921,50 @@ json process_converter(const std::string& topologyName, json converterJson, bool
|
|
|
788
921
|
return process_converter_internal(normalized, converterJson, useNgspice);
|
|
789
922
|
}
|
|
790
923
|
|
|
924
|
+
// Build candidate magnetics from a converter object via the MKF template
|
|
925
|
+
// method, threading the `fast` flag (fast core-only adviser vs full
|
|
926
|
+
// winding+simulation adviser) and optional per-filter weights.
|
|
927
|
+
template <typename ConverterType>
|
|
928
|
+
static std::vector<std::pair<OpenMagnetics::Mas, double>> advise_from_converter_spec(
|
|
929
|
+
const json& converterJson, bool fast,
|
|
930
|
+
const std::map<OpenMagnetics::MagneticFilters, double>& weights,
|
|
931
|
+
int maxResults, OpenMagnetics::MagneticAdviser& adviser) {
|
|
932
|
+
ConverterType converter(converterJson);
|
|
933
|
+
converter._assertErrors = true;
|
|
934
|
+
return weights.empty()
|
|
935
|
+
? adviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
936
|
+
: adviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// Single-inductor, non-isolated family (Buck/Boost/Cuk/Sepic/Zeta/
|
|
940
|
+
// FourSwitchBuckBoost). Their Advanced* class requires ONLY desiredInductance
|
|
941
|
+
// on top of a plain converter spec, so we pick the model purely on the
|
|
942
|
+
// presence of that key: Advanced* when the user pins L (honoured as the
|
|
943
|
+
// nominal target), Base when absent (L derived from the ripple budget in
|
|
944
|
+
// MKF). Transformer/resonant families do NOT get this duality — their
|
|
945
|
+
// Advanced* from_json also requires desiredTurnsRatios (Flyback also
|
|
946
|
+
// desiredDutyCycle), i.e. design *outputs* a converter spec does not carry —
|
|
947
|
+
// so they always use the Base model, which derives turns + L itself.
|
|
948
|
+
template <typename Base, typename Advanced>
|
|
949
|
+
static std::vector<std::pair<OpenMagnetics::Mas, double>> advise_inductor_family(
|
|
950
|
+
const json& converterJson, bool fast,
|
|
951
|
+
const std::map<OpenMagnetics::MagneticFilters, double>& weights,
|
|
952
|
+
int maxResults, OpenMagnetics::MagneticAdviser& adviser) {
|
|
953
|
+
return converterJson.contains("desiredInductance")
|
|
954
|
+
? advise_from_converter_spec<Advanced>(converterJson, fast, weights, maxResults, adviser)
|
|
955
|
+
: advise_from_converter_spec<Base>(converterJson, fast, weights, maxResults, adviser);
|
|
956
|
+
}
|
|
957
|
+
|
|
791
958
|
// Simplified design_magnetics_from_converter using MKF template method
|
|
792
959
|
json design_magnetics_from_converter(
|
|
793
960
|
const std::string& topologyNameRaw,
|
|
794
|
-
json converterJson,
|
|
795
|
-
int maxResults,
|
|
796
|
-
json coreModeJson,
|
|
797
|
-
bool useNgspice,
|
|
798
|
-
json weightsJson
|
|
799
|
-
|
|
800
|
-
|
|
961
|
+
json converterJson,
|
|
962
|
+
int maxResults,
|
|
963
|
+
json coreModeJson,
|
|
964
|
+
bool useNgspice,
|
|
965
|
+
json weightsJson,
|
|
966
|
+
bool fast) {
|
|
967
|
+
|
|
801
968
|
|
|
802
969
|
// Accept MAS 1.0 camelCase, pre-1.0 Title Case, or internal short form.
|
|
803
970
|
const std::string topologyName = normalize_topology_name(topologyNameRaw);
|
|
@@ -821,125 +988,109 @@ json design_magnetics_from_converter(
|
|
|
821
988
|
|
|
822
989
|
std::vector<std::pair<OpenMagnetics::Mas, double>> masMagnetics;
|
|
823
990
|
|
|
824
|
-
//
|
|
825
|
-
//
|
|
826
|
-
// only `magnetizingInductance.minimum` (a ripple-floor), and
|
|
827
|
-
// the CoreAdviser picks the smallest core satisfying it
|
|
828
|
-
// regardless of the L the user asked for. Dispatch to the
|
|
829
|
-
// Advanced* subclass so spec.desiredInductance becomes the
|
|
830
|
-
// nominal target (AdvancedBuck/Boost::process_design_requirements
|
|
831
|
-
// override does this, MKF commit 8acd72c7).
|
|
991
|
+
// Build candidate magnetics from the converter spec via the MKF
|
|
992
|
+
// template method. Two independent axes (4 behaviours total):
|
|
832
993
|
//
|
|
833
|
-
//
|
|
834
|
-
//
|
|
835
|
-
//
|
|
836
|
-
//
|
|
837
|
-
//
|
|
838
|
-
//
|
|
994
|
+
// * Base vs Advanced* model — chosen PER TOPOLOGY:
|
|
995
|
+
// - Single-inductor family (Buck/Boost/Cuk/Sepic/Zeta/
|
|
996
|
+
// FourSwitchBuckBoost): advise_inductor_family() picks
|
|
997
|
+
// Advanced* when desiredInductance is present (honoured as the
|
|
998
|
+
// nominal L target), Base otherwise (L derived from the ripple
|
|
999
|
+
// budget). This is ABT #11 — the slow path used to force
|
|
1000
|
+
// Advanced for Buck/Boost and throw on a base spec.
|
|
1001
|
+
// - Transformer/resonant families: always Base. Their Advanced*
|
|
1002
|
+
// from_json requires desiredTurnsRatios (Flyback also
|
|
1003
|
+
// desiredDutyCycle) — design outputs a converter spec lacks —
|
|
1004
|
+
// so only Base is constructible; it derives turns + L itself.
|
|
1005
|
+
// * fast flag — fast core-only adviser vs full winding+sim adviser,
|
|
1006
|
+
// threaded into get_advised_magnetic_from_converter for every
|
|
1007
|
+
// topology.
|
|
839
1008
|
if (topologyName == "flyback" || topologyName == "advanced_flyback") {
|
|
840
1009
|
OpenMagnetics::Flyback converter(converterJson);
|
|
841
1010
|
converter._assertErrors = true;
|
|
842
1011
|
masMagnetics = weights.empty()
|
|
843
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
844
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1012
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1013
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
845
1014
|
}
|
|
846
1015
|
else if (topologyName == "buck" || topologyName == "advanced_buck") {
|
|
847
|
-
OpenMagnetics::AdvancedBuck
|
|
848
|
-
|
|
849
|
-
masMagnetics = weights.empty()
|
|
850
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
851
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1016
|
+
masMagnetics = advise_inductor_family<OpenMagnetics::Buck, OpenMagnetics::AdvancedBuck>(
|
|
1017
|
+
converterJson, fast, weights, maxResults, magneticAdviser);
|
|
852
1018
|
}
|
|
853
1019
|
else if (topologyName == "boost" || topologyName == "advanced_boost") {
|
|
854
|
-
OpenMagnetics::AdvancedBoost
|
|
855
|
-
|
|
856
|
-
masMagnetics = weights.empty()
|
|
857
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
858
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1020
|
+
masMagnetics = advise_inductor_family<OpenMagnetics::Boost, OpenMagnetics::AdvancedBoost>(
|
|
1021
|
+
converterJson, fast, weights, maxResults, magneticAdviser);
|
|
859
1022
|
}
|
|
860
1023
|
else if (topologyName == "single_switch_forward") {
|
|
861
1024
|
OpenMagnetics::SingleSwitchForward converter(converterJson);
|
|
862
1025
|
converter._assertErrors = true;
|
|
863
1026
|
masMagnetics = weights.empty()
|
|
864
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
865
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1027
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1028
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
866
1029
|
}
|
|
867
1030
|
else if (topologyName == "two_switch_forward") {
|
|
868
1031
|
OpenMagnetics::TwoSwitchForward converter(converterJson);
|
|
869
1032
|
converter._assertErrors = true;
|
|
870
1033
|
masMagnetics = weights.empty()
|
|
871
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
872
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1034
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1035
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
873
1036
|
}
|
|
874
1037
|
else if (topologyName == "active_clamp_forward") {
|
|
875
1038
|
OpenMagnetics::ActiveClampForward converter(converterJson);
|
|
876
1039
|
converter._assertErrors = true;
|
|
877
1040
|
masMagnetics = weights.empty()
|
|
878
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
879
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1041
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1042
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
880
1043
|
}
|
|
881
1044
|
else if (topologyName == "push_pull") {
|
|
882
1045
|
OpenMagnetics::PushPull converter(converterJson);
|
|
883
1046
|
converter._assertErrors = true;
|
|
884
1047
|
masMagnetics = weights.empty()
|
|
885
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
886
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1048
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1049
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
887
1050
|
}
|
|
888
1051
|
else if (topologyName == "isolated_buck") {
|
|
889
1052
|
OpenMagnetics::IsolatedBuck converter(converterJson);
|
|
890
1053
|
converter._assertErrors = true;
|
|
891
1054
|
masMagnetics = weights.empty()
|
|
892
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
893
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1055
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1056
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
894
1057
|
}
|
|
895
1058
|
else if (topologyName == "isolated_buck_boost") {
|
|
896
1059
|
OpenMagnetics::IsolatedBuckBoost converter(converterJson);
|
|
897
1060
|
converter._assertErrors = true;
|
|
898
1061
|
masMagnetics = weights.empty()
|
|
899
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
900
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1062
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1063
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
901
1064
|
}
|
|
902
1065
|
else if (topologyName == "llc" || topologyName == "advanced_llc") {
|
|
903
1066
|
OpenMagnetics::Llc converter(converterJson);
|
|
904
1067
|
converter._assertErrors = true;
|
|
905
1068
|
masMagnetics = weights.empty()
|
|
906
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
907
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1069
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1070
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
908
1071
|
}
|
|
909
1072
|
else if (topologyName == "cuk" || topologyName == "advanced_cuk") {
|
|
910
|
-
OpenMagnetics::Cuk
|
|
911
|
-
|
|
912
|
-
masMagnetics = weights.empty()
|
|
913
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
914
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1073
|
+
masMagnetics = advise_inductor_family<OpenMagnetics::Cuk, OpenMagnetics::AdvancedCuk>(
|
|
1074
|
+
converterJson, fast, weights, maxResults, magneticAdviser);
|
|
915
1075
|
}
|
|
916
1076
|
else if (topologyName == "sepic" || topologyName == "advanced_sepic") {
|
|
917
|
-
OpenMagnetics::Sepic
|
|
918
|
-
|
|
919
|
-
masMagnetics = weights.empty()
|
|
920
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
921
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1077
|
+
masMagnetics = advise_inductor_family<OpenMagnetics::Sepic, OpenMagnetics::AdvancedSepic>(
|
|
1078
|
+
converterJson, fast, weights, maxResults, magneticAdviser);
|
|
922
1079
|
}
|
|
923
1080
|
else if (topologyName == "zeta" || topologyName == "advanced_zeta") {
|
|
924
|
-
OpenMagnetics::Zeta
|
|
925
|
-
|
|
926
|
-
masMagnetics = weights.empty()
|
|
927
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
928
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1081
|
+
masMagnetics = advise_inductor_family<OpenMagnetics::Zeta, OpenMagnetics::AdvancedZeta>(
|
|
1082
|
+
converterJson, fast, weights, maxResults, magneticAdviser);
|
|
929
1083
|
}
|
|
930
1084
|
else if (topologyName == "four_switch_buck_boost" || topologyName == "advanced_four_switch_buck_boost") {
|
|
931
|
-
OpenMagnetics::FourSwitchBuckBoost
|
|
932
|
-
|
|
933
|
-
masMagnetics = weights.empty()
|
|
934
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
935
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1085
|
+
masMagnetics = advise_inductor_family<OpenMagnetics::FourSwitchBuckBoost, OpenMagnetics::AdvancedFourSwitchBuckBoost>(
|
|
1086
|
+
converterJson, fast, weights, maxResults, magneticAdviser);
|
|
936
1087
|
}
|
|
937
1088
|
else if (topologyName == "asymmetric_half_bridge" || topologyName == "advanced_asymmetric_half_bridge") {
|
|
938
1089
|
OpenMagnetics::AsymmetricHalfBridge converter(converterJson);
|
|
939
1090
|
converter._assertErrors = true;
|
|
940
1091
|
masMagnetics = weights.empty()
|
|
941
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
942
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1092
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1093
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
943
1094
|
}
|
|
944
1095
|
else if (topologyName == "phase_shifted_full_bridge" || topologyName == "psfb" ||
|
|
945
1096
|
topologyName == "advanced_phase_shifted_full_bridge" || topologyName == "advanced_psfb") {
|
|
@@ -952,36 +1103,36 @@ json design_magnetics_from_converter(
|
|
|
952
1103
|
OpenMagnetics::Psfb converter(converterJson);
|
|
953
1104
|
converter._assertErrors = true;
|
|
954
1105
|
masMagnetics = weights.empty()
|
|
955
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
956
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1106
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1107
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
957
1108
|
}
|
|
958
1109
|
else if (topologyName == "weinberg" || topologyName == "advanced_weinberg") {
|
|
959
1110
|
OpenMagnetics::Weinberg converter(converterJson);
|
|
960
1111
|
converter._assertErrors = true;
|
|
961
1112
|
masMagnetics = weights.empty()
|
|
962
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
963
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1113
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1114
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
964
1115
|
}
|
|
965
1116
|
else if (topologyName == "vienna" || topologyName == "advanced_vienna") {
|
|
966
1117
|
OpenMagnetics::Vienna converter(converterJson);
|
|
967
1118
|
converter._assertErrors = true;
|
|
968
1119
|
masMagnetics = weights.empty()
|
|
969
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
970
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1120
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1121
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
971
1122
|
}
|
|
972
1123
|
else if (topologyName == "clllc" || topologyName == "advanced_clllc") {
|
|
973
1124
|
OpenMagnetics::Clllc converter(converterJson);
|
|
974
1125
|
converter._assertErrors = true;
|
|
975
1126
|
masMagnetics = weights.empty()
|
|
976
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
977
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1127
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1128
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
978
1129
|
}
|
|
979
1130
|
else if (topologyName == "src" || topologyName == "advanced_src") {
|
|
980
1131
|
OpenMagnetics::Src converter(converterJson);
|
|
981
1132
|
converter._assertErrors = true;
|
|
982
1133
|
masMagnetics = weights.empty()
|
|
983
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
984
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1134
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1135
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
985
1136
|
}
|
|
986
1137
|
else if (topologyName == "dab" || topologyName == "advanced_dab" ||
|
|
987
1138
|
topologyName == "dual_active_bridge") {
|
|
@@ -992,18 +1143,26 @@ json design_magnetics_from_converter(
|
|
|
992
1143
|
OpenMagnetics::Dab converter(converterJson);
|
|
993
1144
|
converter._assertErrors = true;
|
|
994
1145
|
masMagnetics = weights.empty()
|
|
995
|
-
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults)
|
|
996
|
-
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults);
|
|
1146
|
+
? magneticAdviser.get_advised_magnetic_from_converter(converter, maxResults, fast)
|
|
1147
|
+
: magneticAdviser.get_advised_magnetic_from_converter(converter, weights, maxResults, fast);
|
|
997
1148
|
}
|
|
998
1149
|
else {
|
|
999
|
-
// Fall back
|
|
1150
|
+
// Fall back for topologies without a converter-model adviser path
|
|
1151
|
+
// (e.g. PFC, current transformer). dispatch_converter / the
|
|
1152
|
+
// process_*_internal it calls already pick Base vs Advanced on the
|
|
1153
|
+
// presence of desiredInductance (ABT #11), so the Base/Advanced
|
|
1154
|
+
// behaviour is preserved here too; only the adviser stage differs.
|
|
1000
1155
|
json inputsJson = process_converter_internal(topologyName, converterJson, useNgspice);
|
|
1001
1156
|
if (inputsJson.contains("error")) return inputsJson;
|
|
1002
|
-
|
|
1157
|
+
|
|
1003
1158
|
OpenMagnetics::Inputs inputs(inputsJson);
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1159
|
+
if (fast) {
|
|
1160
|
+
masMagnetics = magneticAdviser.get_advised_magnetic_fast(inputs, maxResults);
|
|
1161
|
+
} else if (weights.empty()) {
|
|
1162
|
+
masMagnetics = magneticAdviser.get_advised_magnetic(inputs, maxResults);
|
|
1163
|
+
} else {
|
|
1164
|
+
masMagnetics = magneticAdviser.get_advised_magnetic(inputs, weights, maxResults);
|
|
1165
|
+
}
|
|
1007
1166
|
}
|
|
1008
1167
|
|
|
1009
1168
|
// Build results (same as before)
|
|
@@ -3944,9 +4103,10 @@ void register_converter_bindings(py::module& m) {
|
|
|
3944
4103
|
|
|
3945
4104
|
m.def("design_magnetics_from_converter", &design_magnetics_from_converter,
|
|
3946
4105
|
"Design magnetic components from a converter specification.",
|
|
3947
|
-
py::arg("topology_name"), py::arg("converter_json"),
|
|
4106
|
+
py::arg("topology_name"), py::arg("converter_json"),
|
|
3948
4107
|
py::arg("max_results") = 1, py::arg("core_mode_json") = "available cores",
|
|
3949
|
-
py::arg("use_ngspice") = true, py::arg("weights_json") = nullptr
|
|
4108
|
+
py::arg("use_ngspice") = true, py::arg("weights_json") = nullptr,
|
|
4109
|
+
py::arg("fast") = false);
|
|
3950
4110
|
|
|
3951
4111
|
m.def("process_flyback", &process_flyback, "Process Flyback converter.", py::arg("flyback"));
|
|
3952
4112
|
m.def("process_buck", &process_buck, "Process Buck converter.", py::arg("buck"));
|
|
@@ -9,12 +9,13 @@ json process_converter(const std::string& topologyName, json converterJson, bool
|
|
|
9
9
|
|
|
10
10
|
// Combined endpoint: converter -> magnetic designs
|
|
11
11
|
json design_magnetics_from_converter(
|
|
12
|
-
const std::string& topologyName,
|
|
13
|
-
json converterJson,
|
|
14
|
-
int maxResults,
|
|
15
|
-
json coreModeJson,
|
|
16
|
-
bool useNgspice = true,
|
|
17
|
-
json weightsJson = nullptr
|
|
12
|
+
const std::string& topologyName,
|
|
13
|
+
json converterJson,
|
|
14
|
+
int maxResults,
|
|
15
|
+
json coreModeJson,
|
|
16
|
+
bool useNgspice = true,
|
|
17
|
+
json weightsJson = nullptr,
|
|
18
|
+
bool fast = false);
|
|
18
19
|
|
|
19
20
|
// Per-topology thin wrappers (from .pyi stubs)
|
|
20
21
|
json process_flyback(json flybackJson);
|
|
@@ -322,12 +322,34 @@ double calculate_inductance_from_number_turns_and_gapping(json coreData, json co
|
|
|
322
322
|
return magnetizingInductance;
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
double calculate_number_turns_from_gapping_and_inductance(json coreData, json inputsData, json modelsData) {
|
|
325
|
+
double calculate_number_turns_from_gapping_and_inductance(json coreData, json coilData, json inputsData, json modelsData) {
|
|
326
326
|
OpenMagnetics::Core core(coreData);
|
|
327
|
+
OpenMagnetics::Coil coil(coilData);
|
|
327
328
|
OpenMagnetics::Inputs inputs(inputsData);
|
|
328
329
|
|
|
329
330
|
std::map<std::string, std::string> models = modelsData.get<std::map<std::string, std::string>>();
|
|
330
|
-
|
|
331
|
+
|
|
332
|
+
auto reluctanceModelName = OpenMagnetics::defaults.reluctanceModelDefault;
|
|
333
|
+
if (models.find("reluctance") != models.end()) {
|
|
334
|
+
OpenMagnetics::from_json(models["reluctance"], reluctanceModelName);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
OpenMagnetics::MagnetizingInductance magnetizingInductanceObj(reluctanceModelName);
|
|
338
|
+
double numberTurns = magnetizingInductanceObj.calculate_number_turns_from_gapping_and_inductance(core, coil, &inputs);
|
|
339
|
+
|
|
340
|
+
return numberTurns;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Legacy 3-argument variant (no coil_data). Backward-compat shim for callers
|
|
344
|
+
// written before the coil parameter was added; forwards to MKF's 3-argument
|
|
345
|
+
// overload, which synthesizes a single-primary-winding coil internally. New
|
|
346
|
+
// code should pass coil_data and use the 4-argument form above.
|
|
347
|
+
double calculate_number_turns_from_gapping_and_inductance_legacy(json coreData, json inputsData, json modelsData) {
|
|
348
|
+
OpenMagnetics::Core core(coreData);
|
|
349
|
+
OpenMagnetics::Inputs inputs(inputsData);
|
|
350
|
+
|
|
351
|
+
std::map<std::string, std::string> models = modelsData.get<std::map<std::string, std::string>>();
|
|
352
|
+
|
|
331
353
|
auto reluctanceModelName = OpenMagnetics::defaults.reluctanceModelDefault;
|
|
332
354
|
if (models.find("reluctance") != models.end()) {
|
|
333
355
|
OpenMagnetics::from_json(models["reluctance"], reluctanceModelName);
|
|
@@ -960,14 +982,36 @@ void register_core_bindings(py::module& m) {
|
|
|
960
982
|
|
|
961
983
|
Args:
|
|
962
984
|
core_data: JSON object with core specification.
|
|
985
|
+
coil_data: JSON object with coil/winding specification.
|
|
963
986
|
inputs_data: JSON Inputs with magnetizingInductance requirement.
|
|
964
987
|
models_data: JSON dict with "reluctance" model selection.
|
|
965
|
-
|
|
988
|
+
|
|
989
|
+
Returns:
|
|
990
|
+
Required number of turns (may be non-integer).
|
|
991
|
+
)pbdoc",
|
|
992
|
+
py::arg("core_data"), py::arg("coil_data"), py::arg("inputs_data"), py::arg("models_data"));
|
|
993
|
+
|
|
994
|
+
// Legacy 3-argument overload (no coil_data) registered under the SAME name:
|
|
995
|
+
// pybind dispatches by arity, so existing 3-arg callers keep working while
|
|
996
|
+
// new code uses the coil-aware 4-arg form above (the canonical default).
|
|
997
|
+
m.def("calculate_number_turns_from_gapping_and_inductance", &calculate_number_turns_from_gapping_and_inductance_legacy,
|
|
998
|
+
R"pbdoc(
|
|
999
|
+
Legacy variant of calculate_number_turns_from_gapping_and_inductance
|
|
1000
|
+
without coil_data (kept for backward compatibility).
|
|
1001
|
+
|
|
1002
|
+
Synthesizes a single-primary-winding coil internally. Prefer the
|
|
1003
|
+
coil-aware 4-argument form for multi-winding designs.
|
|
1004
|
+
|
|
1005
|
+
Args:
|
|
1006
|
+
core_data: JSON object with core specification.
|
|
1007
|
+
inputs_data: JSON Inputs with magnetizingInductance requirement.
|
|
1008
|
+
models_data: JSON dict with "reluctance" model selection.
|
|
1009
|
+
|
|
966
1010
|
Returns:
|
|
967
1011
|
Required number of turns (may be non-integer).
|
|
968
1012
|
)pbdoc",
|
|
969
1013
|
py::arg("core_data"), py::arg("inputs_data"), py::arg("models_data"));
|
|
970
|
-
|
|
1014
|
+
|
|
971
1015
|
m.def("calculate_gapping_from_number_turns_and_inductance", &calculate_gapping_from_number_turns_and_inductance,
|
|
972
1016
|
R"pbdoc(
|
|
973
1017
|
Calculate required gap from turns count and target inductance.
|
|
@@ -43,7 +43,8 @@ double calculate_temperature_from_core_thermal_resistance(json coreJson, double
|
|
|
43
43
|
json calculate_gap_reluctance(json coreGapData, std::string modelNameString);
|
|
44
44
|
json get_gap_reluctance_model_information();
|
|
45
45
|
double calculate_inductance_from_number_turns_and_gapping(json coreData, json coilData, json operatingPointData, json modelsData);
|
|
46
|
-
double calculate_number_turns_from_gapping_and_inductance(json coreData, json inputsData, json modelsData);
|
|
46
|
+
double calculate_number_turns_from_gapping_and_inductance(json coreData, json coilData, json inputsData, json modelsData);
|
|
47
|
+
double calculate_number_turns_from_gapping_and_inductance_legacy(json coreData, json inputsData, json modelsData);
|
|
47
48
|
json calculate_gapping_from_number_turns_and_inductance(json coreData, json coilData, json inputsData, std::string gappingTypeJson, int decimals, json modelsData);
|
|
48
49
|
|
|
49
50
|
// Shape queries by family/manufacturer
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|