PyOpenMagnetics 1.5.0__tar.gz → 1.5.1__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.5.0 → pyopenmagnetics-1.5.1}/CMakeLists.txt +9 -1
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/PKG-INFO +1 -1
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/complete_simulation_example.py +1 -2
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_220v_12v_1a.py +1 -2
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_220v_12v_2a_complete.py +1 -2
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_design.py +1 -2
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/pyproject.toml +1 -1
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/core.cpp +98 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/core.h +1 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/losses.cpp +0 -23
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/losses.h +0 -1
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/simulation.cpp +1 -6
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_core.py +84 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/.github/workflows/ci.yml +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/.github/workflows/publish.yml +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/.gitignore +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/AGENTS.md +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/LICENSE +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/PyOpenMagnetics.pyi +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/README.md +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/__init__.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/api/MAS.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/api/mas_db_reader.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/api/validation.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/clear_cibuildwheel_cache.sh +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/docs/compatibility.md +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/docs/errors.md +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/docs/performance.md +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/README.md +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/buck_inductor.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/converter_design_example.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/debug_bobbin.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/debug_coil.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/debug_core.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/debug_plotting.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_bh_curve.png +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_core.png +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_summary.png +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_waveforms.png +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/list_plot_funcs.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/plot_flyback_design.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/plot_flyback_pyom.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/test_field_calc.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/test_field_plot.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/force_fresh_build.sh +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/llms.txt +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/notebooks/01_getting_started.ipynb +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/notebooks/02_buck_inductor.ipynb +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/notebooks/03_core_losses.ipynb +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/notebooks/README.md +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/requirements.txt +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/advisers.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/advisers.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/bobbin.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/bobbin.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/common.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/converter.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/converter.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/database.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/database.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/logging.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/logging.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/module.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/plotting.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/plotting.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/settings.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/settings.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/simulation.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/utils.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/utils.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/winding.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/winding.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/wire.cpp +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/wire.h +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/test.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/__init__.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/conftest.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_converter_endpoints.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_core_adviser.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_examples_integration.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_inputs.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_logging.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_magnetic_adviser.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_plotting.py +0 -0
- {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_winding.py +0 -0
|
@@ -218,7 +218,15 @@ add_custom_command(
|
|
|
218
218
|
OUTPUT "${MAS_DIRECTORY}/MAS.hpp"
|
|
219
219
|
# Force regeneration by removing output first
|
|
220
220
|
COMMAND ${CMAKE_COMMAND} -E remove -f ${MAS_DIRECTORY}/MAS.hpp
|
|
221
|
-
COMMAND quicktype -l c++ -s schema ${MAS_DIR}/schemas/MAS.json
|
|
221
|
+
COMMAND quicktype -l c++ -s schema ${MAS_DIR}/schemas/MAS.json
|
|
222
|
+
# PEAS schemas: MAS main ($id https://psma.com/mas/...) now $refs shared
|
|
223
|
+
# PEAS primitives (https://psma.com/peas/...). quicktype resolves those
|
|
224
|
+
# external $refs by $id from sources passed with -S, so the PEAS schemas
|
|
225
|
+
# must be fed in here. PEAS is an MKF submodule at ${MKF_DIR}/PEAS.
|
|
226
|
+
-S ${MKF_DIR}/PEAS/schemas/utils.json
|
|
227
|
+
-S ${MKF_DIR}/PEAS/schemas/inputs/operatingPointExcitation.json
|
|
228
|
+
-S ${MKF_DIR}/PEAS/schemas/outputs/insulationCoordination.json
|
|
229
|
+
-S ${MKF_DIR}/PEAS/schemas/outputs/lossElementPerHarmonic.json
|
|
222
230
|
-S ${MAS_DIR}/schemas/magnetic.json
|
|
223
231
|
-S ${MAS_DIR}/schemas/magnetic/core.json
|
|
224
232
|
-S ${MAS_DIR}/schemas/magnetic/coil.json
|
|
@@ -430,6 +430,70 @@ double calculate_saturation_current_at_operating_point(
|
|
|
430
430
|
return magnetic.calculate_saturation_current(op, temperature);
|
|
431
431
|
}
|
|
432
432
|
|
|
433
|
+
double calculate_peak_winding_current(json magneticJson, json operatingPointJson, int windingIndex) {
|
|
434
|
+
OpenMagnetics::Magnetic magnetic(magneticJson);
|
|
435
|
+
MAS::OperatingPoint op;
|
|
436
|
+
from_json(operatingPointJson, op);
|
|
437
|
+
|
|
438
|
+
// Operating-point magnetizing inductance of the as-designed magnetic
|
|
439
|
+
// (gapped circuit + DC-bias rolloff). Same L the saturation-current
|
|
440
|
+
// accessor uses, so I_peak and I_sat stay on a consistent footing.
|
|
441
|
+
OpenMagnetics::MagnetizingInductance magnetizingInductanceCalc;
|
|
442
|
+
auto inductanceOutput =
|
|
443
|
+
magnetizingInductanceCalc.calculate_inductance_from_number_turns_and_gapping(
|
|
444
|
+
magnetic.get_mutable_core(), magnetic.get_mutable_coil(), &op);
|
|
445
|
+
auto inductanceNominal = inductanceOutput.get_magnetizing_inductance().get_nominal();
|
|
446
|
+
if (!inductanceNominal.has_value() || inductanceNominal.value() <= 0) {
|
|
447
|
+
throw std::runtime_error(
|
|
448
|
+
"calculate_peak_winding_current: operating-point magnetizing "
|
|
449
|
+
"inductance is missing or non-positive — cannot derive the "
|
|
450
|
+
"magnetizing current.");
|
|
451
|
+
}
|
|
452
|
+
double magnetizingInductance = inductanceNominal.value();
|
|
453
|
+
|
|
454
|
+
auto excitations = op.get_mutable_excitations_per_winding();
|
|
455
|
+
if (excitations.empty()) {
|
|
456
|
+
throw std::runtime_error(
|
|
457
|
+
"calculate_peak_winding_current: operating point has no winding "
|
|
458
|
+
"excitations.");
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// The magnetizing (flux-driving) current is referred to the primary
|
|
462
|
+
// (winding 0): I_mag = (1/L) ∫ v_primary dt, derived from the primary
|
|
463
|
+
// excitation's voltage. addOffset=true folds the operating DC bias of
|
|
464
|
+
// the primary current back in, so the returned peak is the saturation-
|
|
465
|
+
// driving peak (DC + ripple), not just the AC ripple amplitude.
|
|
466
|
+
auto primaryExcitation = excitations[0];
|
|
467
|
+
auto magnetizingCurrent = OpenMagnetics::Inputs::calculate_magnetizing_current(
|
|
468
|
+
primaryExcitation, magnetizingInductance, true, true);
|
|
469
|
+
auto processed = magnetizingCurrent.get_processed();
|
|
470
|
+
if (!processed.has_value() || !processed->get_peak().has_value()) {
|
|
471
|
+
throw std::runtime_error(
|
|
472
|
+
"calculate_peak_winding_current: computed magnetizing current has "
|
|
473
|
+
"no processed peak.");
|
|
474
|
+
}
|
|
475
|
+
double primaryPeak = processed->get_peak().value();
|
|
476
|
+
|
|
477
|
+
if (windingIndex == 0) {
|
|
478
|
+
return primaryPeak;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Saturation is a single-flux core property; the magnetizing current
|
|
482
|
+
// referred to winding i is the primary-referred value scaled by the
|
|
483
|
+
// turns ratio: I_mag_i = I_mag_0 · N_0 / N_i.
|
|
484
|
+
double numberTurnsPrimary =
|
|
485
|
+
static_cast<double>(magnetic.get_mutable_coil().get_number_turns(0));
|
|
486
|
+
double numberTurnsWinding =
|
|
487
|
+
static_cast<double>(magnetic.get_mutable_coil().get_number_turns(windingIndex));
|
|
488
|
+
if (numberTurnsWinding <= 0) {
|
|
489
|
+
throw std::runtime_error(
|
|
490
|
+
"calculate_peak_winding_current: winding " +
|
|
491
|
+
std::to_string(windingIndex) + " has no turns — cannot refer the "
|
|
492
|
+
"magnetizing current to it.");
|
|
493
|
+
}
|
|
494
|
+
return primaryPeak * numberTurnsPrimary / numberTurnsWinding;
|
|
495
|
+
}
|
|
496
|
+
|
|
433
497
|
double calculate_temperature_from_core_thermal_resistance(json coreJson, double totalLosses) {
|
|
434
498
|
OpenMagnetics::Core core(coreJson);
|
|
435
499
|
|
|
@@ -1073,6 +1137,40 @@ void register_core_bindings(py::module& m) {
|
|
|
1073
1137
|
py::arg("magnetic_json"), py::arg("operating_point_json"),
|
|
1074
1138
|
py::arg("temperature"));
|
|
1075
1139
|
|
|
1140
|
+
m.def("calculate_peak_winding_current",
|
|
1141
|
+
&calculate_peak_winding_current,
|
|
1142
|
+
R"pbdoc(
|
|
1143
|
+
Peak magnetizing (flux-driving) current at an operating point.
|
|
1144
|
+
|
|
1145
|
+
Returns the peak of the magnetizing current — the quantity that
|
|
1146
|
+
actually drives core flux and therefore saturation — for the
|
|
1147
|
+
as-designed magnetic at the supplied operating point. This is the
|
|
1148
|
+
consistent partner to ``calculate_saturation_current_at_operating_point``:
|
|
1149
|
+
both use the same operating-point magnetizing inductance, so the
|
|
1150
|
+
caller can compare I_peak against I_sat on the same footing.
|
|
1151
|
+
|
|
1152
|
+
The magnetizing current is computed by MKF from the primary voltage
|
|
1153
|
+
waveform (``I_mag = (1/L) ∫ v dt``) with the operating DC bias folded
|
|
1154
|
+
in, NOT read back from the input current. For a transformer this is
|
|
1155
|
+
the genuine flux-driving current, which differs from the primary
|
|
1156
|
+
winding current (the latter includes reflected load current that
|
|
1157
|
+
produces no net flux).
|
|
1158
|
+
|
|
1159
|
+
Args:
|
|
1160
|
+
magnetic_json: JSON Magnetic object (core + coil).
|
|
1161
|
+
operating_point_json: JSON OperatingPoint object with at least the
|
|
1162
|
+
primary winding voltage excitation.
|
|
1163
|
+
winding_index: Winding the result is referred to (default 0,
|
|
1164
|
+
primary). For other windings the primary-referred peak is
|
|
1165
|
+
scaled by the turns ratio N_0 / N_i — saturation is a single
|
|
1166
|
+
core-flux property, so this is largely a unit choice.
|
|
1167
|
+
|
|
1168
|
+
Returns:
|
|
1169
|
+
Peak magnetizing current in Amperes.
|
|
1170
|
+
)pbdoc",
|
|
1171
|
+
py::arg("magnetic_json"), py::arg("operating_point_json"),
|
|
1172
|
+
py::arg("winding_index") = 0);
|
|
1173
|
+
|
|
1076
1174
|
m.def("calculate_saturation_current", &calculate_saturation_current,
|
|
1077
1175
|
R"pbdoc(
|
|
1078
1176
|
Calculate saturation current for a complete magnetic.
|
|
@@ -37,6 +37,7 @@ json load_core_data(json coresJson);
|
|
|
37
37
|
json get_core_temperature_dependant_parameters(json coreData, double temperature);
|
|
38
38
|
double calculate_core_maximum_magnetic_energy(json coreDataJson, json operatingPointJson);
|
|
39
39
|
double calculate_saturation_current(json magneticJson, double temperature);
|
|
40
|
+
double calculate_peak_winding_current(json magneticJson, json operatingPointJson, int windingIndex);
|
|
40
41
|
double calculate_temperature_from_core_thermal_resistance(json coreJson, double totalLosses);
|
|
41
42
|
|
|
42
43
|
// Gap and reluctance
|
|
@@ -25,10 +25,6 @@ json calculate_core_losses(json coreData, json coilData, json inputsData, json m
|
|
|
25
25
|
if (models.find("coreLosses") != models.end()) {
|
|
26
26
|
OpenMagnetics::from_json(models["coreLosses"], coreLossesModelName);
|
|
27
27
|
}
|
|
28
|
-
auto coreTemperatureModelName = OpenMagnetics::defaults.coreTemperatureModelDefault;
|
|
29
|
-
if (models.find("coreTemperature") != models.end()) {
|
|
30
|
-
OpenMagnetics::from_json(models["coreTemperature"], coreTemperatureModelName);
|
|
31
|
-
}
|
|
32
28
|
|
|
33
29
|
OpenMagnetics::Magnetic magnetic;
|
|
34
30
|
magnetic.set_core(core);
|
|
@@ -36,7 +32,6 @@ json calculate_core_losses(json coreData, json coilData, json inputsData, json m
|
|
|
36
32
|
|
|
37
33
|
OpenMagnetics::MagneticSimulator magneticSimulator;
|
|
38
34
|
magneticSimulator.set_core_losses_model_name(coreLossesModelName);
|
|
39
|
-
magneticSimulator.set_core_temperature_model_name(coreTemperatureModelName);
|
|
40
35
|
magneticSimulator.set_reluctance_model_name(reluctanceModelName);
|
|
41
36
|
auto coreLossesOutput = magneticSimulator.calculate_core_losses(operatingPoint, magnetic);
|
|
42
37
|
json result;
|
|
@@ -66,15 +61,6 @@ json get_core_losses_model_information(json material) {
|
|
|
66
61
|
return info;
|
|
67
62
|
}
|
|
68
63
|
|
|
69
|
-
json get_core_temperature_model_information() {
|
|
70
|
-
json info;
|
|
71
|
-
info["information"] = OpenMagnetics::CoreTemperatureModel::get_models_information();
|
|
72
|
-
info["errors"] = OpenMagnetics::CoreTemperatureModel::get_models_errors();
|
|
73
|
-
info["internal_links"] = OpenMagnetics::CoreTemperatureModel::get_models_internal_links();
|
|
74
|
-
info["external_links"] = OpenMagnetics::CoreTemperatureModel::get_models_external_links();
|
|
75
|
-
return info;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
64
|
json calculate_steinmetz_coefficients(json dataJson, json rangesJson) {
|
|
79
65
|
try {
|
|
80
66
|
std::vector<std::pair<double, double>> ranges;
|
|
@@ -383,7 +369,6 @@ void register_losses_bindings(py::module& m) {
|
|
|
383
369
|
models_data: JSON dict specifying models to use:
|
|
384
370
|
- "coreLosses": "STEINMETZ", "IGSE", "MSE", "BARG", "ROSHEN", "PROPRIETARY"
|
|
385
371
|
- "reluctance": "ZHANG", "MUEHLETHALER", "PARTRIDGE", "STENGLEIN"
|
|
386
|
-
- "coreTemperature": Model for temperature estimation
|
|
387
372
|
|
|
388
373
|
Returns:
|
|
389
374
|
JSON object containing:
|
|
@@ -423,14 +408,6 @@ void register_losses_bindings(py::module& m) {
|
|
|
423
408
|
)pbdoc",
|
|
424
409
|
py::arg("material"));
|
|
425
410
|
|
|
426
|
-
m.def("get_core_temperature_model_information", &get_core_temperature_model_information,
|
|
427
|
-
R"pbdoc(
|
|
428
|
-
Get documentation for available core temperature models.
|
|
429
|
-
|
|
430
|
-
Returns:
|
|
431
|
-
JSON object with model information, errors, and reference links.
|
|
432
|
-
)pbdoc");
|
|
433
|
-
|
|
434
411
|
m.def("calculate_steinmetz_coefficients", &calculate_steinmetz_coefficients,
|
|
435
412
|
R"pbdoc(
|
|
436
413
|
Fit Steinmetz equation coefficients from measured loss data.
|
|
@@ -7,7 +7,6 @@ namespace PyMKF {
|
|
|
7
7
|
// Core losses
|
|
8
8
|
json calculate_core_losses(json coreData, json coilData, json inputsData, json modelsData);
|
|
9
9
|
json get_core_losses_model_information(json material);
|
|
10
|
-
json get_core_temperature_model_information();
|
|
11
10
|
json calculate_steinmetz_coefficients(json dataJson, json rangesJson);
|
|
12
11
|
json calculate_steinmetz_coefficients_with_error(json dataJson, json rangesJson);
|
|
13
12
|
|
|
@@ -15,14 +15,9 @@ json simulate(json inputsJson, json magneticJson, json modelsData) {
|
|
|
15
15
|
if (!modelsData.is_null() && modelsData.find("coreLosses") != modelsData.end()) {
|
|
16
16
|
OpenMagnetics::from_json(modelsData["coreLosses"], coreLossesModelName);
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
if (!modelsData.is_null() && modelsData.find("coreTemperature") != modelsData.end()) {
|
|
20
|
-
OpenMagnetics::from_json(modelsData["coreTemperature"], coreTemperatureModelName);
|
|
21
|
-
}
|
|
22
|
-
|
|
18
|
+
|
|
23
19
|
OpenMagnetics::MagneticSimulator magneticSimulator;
|
|
24
20
|
magneticSimulator.set_core_losses_model_name(coreLossesModelName);
|
|
25
|
-
magneticSimulator.set_core_temperature_model_name(coreTemperatureModelName);
|
|
26
21
|
magneticSimulator.set_reluctance_model_name(reluctanceModelName);
|
|
27
22
|
auto mas = magneticSimulator.simulate(inputs, magnetic);
|
|
28
23
|
|
|
@@ -181,6 +181,90 @@ class TestCoreCalculations:
|
|
|
181
181
|
assert isinstance(gapping, list)
|
|
182
182
|
|
|
183
183
|
|
|
184
|
+
class TestPeakWindingCurrent:
|
|
185
|
+
"""
|
|
186
|
+
Tests for calculate_peak_winding_current (ABT #16).
|
|
187
|
+
|
|
188
|
+
Verifies the binding that exposes the MKF-computed peak magnetizing
|
|
189
|
+
(flux-driving) current at an operating point, so Heaviside no longer
|
|
190
|
+
needs analytical I_peak fallbacks.
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
def _advise_magnetic(self, inputs):
|
|
194
|
+
proc = PyOpenMagnetics.process_inputs(inputs)
|
|
195
|
+
res = PyOpenMagnetics.calculate_advised_magnetics(proc, 1, "available cores")
|
|
196
|
+
data = json.loads(res) if isinstance(res, str) else res
|
|
197
|
+
data = data["data"] if isinstance(data, dict) and "data" in data else data
|
|
198
|
+
assert len(data) > 0, "adviser returned no magnetic"
|
|
199
|
+
mas = data[0].get("mas", data[0])
|
|
200
|
+
return mas["magnetic"], mas["inputs"]["operatingPoints"][0]
|
|
201
|
+
|
|
202
|
+
def test_inductor_peak_includes_dc_bias(self):
|
|
203
|
+
"""
|
|
204
|
+
Peak magnetizing current must fold in the operating DC bias, not
|
|
205
|
+
return only the AC ripple amplitude. Input current here is a 5 A DC
|
|
206
|
+
bias with a 4 A peak-to-peak ripple.
|
|
207
|
+
"""
|
|
208
|
+
op = {
|
|
209
|
+
"name": "Nominal",
|
|
210
|
+
"conditions": {"ambientTemperature": 25},
|
|
211
|
+
"excitationsPerWinding": [{
|
|
212
|
+
"frequency": 100000,
|
|
213
|
+
"current": {"waveform": {"data": [3, 7, 3],
|
|
214
|
+
"time": [0, 0.0000025, 0.00001]}},
|
|
215
|
+
"voltage": {"waveform": {"data": [-10, 30, 30, -10, -10],
|
|
216
|
+
"time": [0, 0, 0.0000025, 0.0000025, 0.00001]}},
|
|
217
|
+
}],
|
|
218
|
+
}
|
|
219
|
+
inputs = {
|
|
220
|
+
"designRequirements": {"magnetizingInductance": {"nominal": 100e-6},
|
|
221
|
+
"turnsRatios": []},
|
|
222
|
+
"operatingPoints": [op],
|
|
223
|
+
}
|
|
224
|
+
magnetic, op_used = self._advise_magnetic(inputs)
|
|
225
|
+
|
|
226
|
+
ipeak = PyOpenMagnetics.calculate_peak_winding_current(magnetic, op_used, 0)
|
|
227
|
+
# Default winding_index argument must match explicit 0.
|
|
228
|
+
assert ipeak == PyOpenMagnetics.calculate_peak_winding_current(magnetic, op_used)
|
|
229
|
+
assert ipeak > 0
|
|
230
|
+
# Must include the ~5 A DC bias, so well above the bare ripple amplitude.
|
|
231
|
+
assert ipeak > 4.0
|
|
232
|
+
|
|
233
|
+
# Consistent footing with I_sat at the same operating point.
|
|
234
|
+
isat = PyOpenMagnetics.calculate_saturation_current_at_operating_point(
|
|
235
|
+
magnetic, op_used, 25.0)
|
|
236
|
+
assert isat > ipeak # an advised design should not be saturating
|
|
237
|
+
|
|
238
|
+
def test_transformer_winding_index_scales_by_turns_ratio(self):
|
|
239
|
+
"""
|
|
240
|
+
For a transformer the per-winding magnetizing peak is the primary
|
|
241
|
+
value scaled by the turns ratio N_0 / N_i.
|
|
242
|
+
"""
|
|
243
|
+
op = {
|
|
244
|
+
"name": "Nominal",
|
|
245
|
+
"conditions": {"ambientTemperature": 25},
|
|
246
|
+
"excitationsPerWinding": [{
|
|
247
|
+
"frequency": 100000,
|
|
248
|
+
"current": {"waveform": {"data": [-5, 5, -5],
|
|
249
|
+
"time": [0, 0.0000025, 0.00001]}},
|
|
250
|
+
"voltage": {"waveform": {"data": [-10, 30, 30, -10, -10],
|
|
251
|
+
"time": [0, 0, 0.0000025, 0.0000025, 0.00001]}},
|
|
252
|
+
}],
|
|
253
|
+
}
|
|
254
|
+
inputs = {
|
|
255
|
+
"designRequirements": {"magnetizingInductance": {"nominal": 100e-6},
|
|
256
|
+
"turnsRatios": [{"nominal": 2.0}]},
|
|
257
|
+
"operatingPoints": [op],
|
|
258
|
+
}
|
|
259
|
+
magnetic, op_used = self._advise_magnetic(inputs)
|
|
260
|
+
turns = [w["numberTurns"]
|
|
261
|
+
for w in magnetic["coil"]["functionalDescription"]]
|
|
262
|
+
|
|
263
|
+
p0 = PyOpenMagnetics.calculate_peak_winding_current(magnetic, op_used, 0)
|
|
264
|
+
p1 = PyOpenMagnetics.calculate_peak_winding_current(magnetic, op_used, 1)
|
|
265
|
+
assert p1 == pytest.approx(p0 * turns[0] / turns[1], rel=1e-9)
|
|
266
|
+
|
|
267
|
+
|
|
184
268
|
class TestCoreProcessedDescription:
|
|
185
269
|
"""Test suite for processed core descriptions."""
|
|
186
270
|
|
|
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
|