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.
Files changed (85) hide show
  1. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/CMakeLists.txt +9 -1
  2. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/PKG-INFO +1 -1
  3. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/complete_simulation_example.py +1 -2
  4. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_220v_12v_1a.py +1 -2
  5. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_220v_12v_2a_complete.py +1 -2
  6. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_design.py +1 -2
  7. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/pyproject.toml +1 -1
  8. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/core.cpp +98 -0
  9. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/core.h +1 -0
  10. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/losses.cpp +0 -23
  11. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/losses.h +0 -1
  12. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/simulation.cpp +1 -6
  13. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_core.py +84 -0
  14. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/.github/workflows/ci.yml +0 -0
  15. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/.github/workflows/publish.yml +0 -0
  16. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/.gitignore +0 -0
  17. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/AGENTS.md +0 -0
  18. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/LICENSE +0 -0
  19. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/PyOpenMagnetics.pyi +0 -0
  20. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/README.md +0 -0
  21. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/__init__.py +0 -0
  22. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/api/MAS.py +0 -0
  23. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/api/mas_db_reader.py +0 -0
  24. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/api/validation.py +0 -0
  25. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/clear_cibuildwheel_cache.sh +0 -0
  26. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/docs/compatibility.md +0 -0
  27. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/docs/errors.md +0 -0
  28. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/docs/performance.md +0 -0
  29. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/README.md +0 -0
  30. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/buck_inductor.py +0 -0
  31. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/converter_design_example.py +0 -0
  32. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/debug_bobbin.py +0 -0
  33. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/debug_coil.py +0 -0
  34. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/debug_core.py +0 -0
  35. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/debug_plotting.py +0 -0
  36. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_bh_curve.png +0 -0
  37. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_core.png +0 -0
  38. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_summary.png +0 -0
  39. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/flyback_waveforms.png +0 -0
  40. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/list_plot_funcs.py +0 -0
  41. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/plot_flyback_design.py +0 -0
  42. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/plot_flyback_pyom.py +0 -0
  43. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/test_field_calc.py +0 -0
  44. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/examples/test_field_plot.py +0 -0
  45. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/force_fresh_build.sh +0 -0
  46. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/llms.txt +0 -0
  47. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/notebooks/01_getting_started.ipynb +0 -0
  48. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/notebooks/02_buck_inductor.ipynb +0 -0
  49. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/notebooks/03_core_losses.ipynb +0 -0
  50. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/notebooks/README.md +0 -0
  51. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/requirements.txt +0 -0
  52. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/advisers.cpp +0 -0
  53. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/advisers.h +0 -0
  54. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/bobbin.cpp +0 -0
  55. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/bobbin.h +0 -0
  56. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/common.h +0 -0
  57. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/converter.cpp +0 -0
  58. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/converter.h +0 -0
  59. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/database.cpp +0 -0
  60. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/database.h +0 -0
  61. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/logging.cpp +0 -0
  62. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/logging.h +0 -0
  63. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/module.cpp +0 -0
  64. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/plotting.cpp +0 -0
  65. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/plotting.h +0 -0
  66. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/settings.cpp +0 -0
  67. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/settings.h +0 -0
  68. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/simulation.h +0 -0
  69. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/utils.cpp +0 -0
  70. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/utils.h +0 -0
  71. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/winding.cpp +0 -0
  72. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/winding.h +0 -0
  73. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/wire.cpp +0 -0
  74. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/src/wire.h +0 -0
  75. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/test.py +0 -0
  76. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/__init__.py +0 -0
  77. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/conftest.py +0 -0
  78. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_converter_endpoints.py +0 -0
  79. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_core_adviser.py +0 -0
  80. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_examples_integration.py +0 -0
  81. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_inputs.py +0 -0
  82. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_logging.py +0 -0
  83. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_magnetic_adviser.py +0 -0
  84. {pyopenmagnetics-1.5.0 → pyopenmagnetics-1.5.1}/tests/test_plotting.py +0 -0
  85. {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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: PyOpenMagnetics
3
- Version: 1.5.0
3
+ Version: 1.5.1
4
4
  Summary: Python wrapper for OpenMagnetics
5
5
  Author-Email: Alfonso Martinez <Alfonso_VII@hotmail.com>
6
6
  Classifier: Development Status :: 4 - Beta
@@ -179,8 +179,7 @@ def simulate_losses(magnetic, specs):
179
179
  print("\n[1] Calculating core losses...")
180
180
  models = {
181
181
  "coreLosses": "IGSE",
182
- "reluctance": "ZHANG",
183
- "coreTemperature": "MANIKTALA"
182
+ "reluctance": "ZHANG"
184
183
  }
185
184
 
186
185
  try:
@@ -287,8 +287,7 @@ def design_flyback_transformer():
287
287
 
288
288
  models = {
289
289
  "coreLosses": "IGSE",
290
- "reluctance": "ZHANG",
291
- "coreTemperature": "MANIKTALA"
290
+ "reluctance": "ZHANG"
292
291
  }
293
292
 
294
293
  best_design = None
@@ -301,8 +301,7 @@ def design_flyback_transformer():
301
301
 
302
302
  models = {
303
303
  "coreLosses": "IGSE",
304
- "reluctance": "ZHANG",
305
- "coreTemperature": "MANIKTALA"
304
+ "reluctance": "ZHANG"
306
305
  }
307
306
 
308
307
  best_design = None
@@ -127,8 +127,7 @@ def design_flyback_transformer():
127
127
 
128
128
  models = {
129
129
  "coreLosses": "IGSE",
130
- "reluctance": "ZHANG",
131
- "coreTemperature": "MANIKTALA"
130
+ "reluctance": "ZHANG"
132
131
  }
133
132
 
134
133
  for i, item in enumerate(magnetics):
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "PyOpenMagnetics"
7
- version = "1.5.0"
7
+ version = "1.5.1"
8
8
  requires-python = ">=3.8"
9
9
  authors = [
10
10
  { name="Alfonso Martinez", email="Alfonso_VII@hotmail.com" },
@@ -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
- auto coreTemperatureModelName = OpenMagnetics::defaults.coreTemperatureModelDefault;
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