Repository navigation
Add the Python dq transform, its tests, and the Ansys/Python boundary rule - #31
Conversation
|
@smidl Do we want to have |
|
@saxik13 Do I remember correctly that you once told me that you generate |
… rule Addresses the additive half of #25. The same Park/Clarke transform is written out by hand three times in `motors/synrm_5f_40s.py`'s output variables -- once for flux linkage, once for input current, once for terminal voltage -- off one pair of cos/sin tables. None of it needs the field solution; it is algebra on quantities the solve has already produced. This adds the Python side and the rule, and removes nothing: machine_design/transforms.py the transform once: to_dq / to_phases / electrical_angle, matching the Ansys convention exactly, including the sin(-h*(...)) sign that makes q the negative sine sum tests/test_transforms.py pins that convention offline (no Ansys) tests/test_ansys_transforms.py live cross-check on one solve, both subspaces excited CONTRIBUTING.md "What runs in Ansys, what runs in Python" Phase count is not hard-coded. `to_dq` reads it off the last axis of its input, so the same function serves the 3-phase anchor and the 5-phase one; `to_phases` takes it explicitly, having no input array to read it from. The offline tests are parametrised over (phase count, harmonic), and the m=3/h=3 triplen case -- zero-sequence, so not invertible -- is pinned as such so nobody "fixes" it. Verified on a live AEDT 2024.2 solve (bayes, 1 core): the Python transform reproduces Ansys's own dq output variables to 2.3e-15 (dq1) and 2.5e-16 (dq3) -- floating-point exact, not within a tolerance. Two things that verification turned up, both now recorded: * Ansys returns `theta_el` in DEGREES, not radians -- the `- pi` in its expression is evaluated as -180 in an angular context. The Ansys side is correct and internally consistent (theta_el is only ever used inside cos/sin as angle-minus-angle), but a Python consumer reading the raw number gets silent nonsense. `electrical_angle()` therefore takes an explicit `degrees=` flag and always returns radians. * `Flux_d1..q3` are defined as output variables but never extracted -- `solution_expressions` requests `Flux_e_*` (excitation flux) instead. So the flux transforms are computed by Ansys and discarded. The cross-check covers flux AND voltage deliberately. Flux stays in Ansys (it needs the solve), so that half is a permanent guard on the boundary. The voltage half is a one-shot equivalence proof: the Ansys-side voltage variables are slated to move to Python, which deletes both sides of the comparison, so it can only be run while they still exist. No behaviour change: three new files plus a CONTRIBUTING section. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
7a0474e to
f42372e
Compare
Agreed — done, and the phase count turned out not to need to be an argument in the main case: d1, q1 = to_dq(phase_values, theta_el, harmonic=1) # 3-phase or 5-phase, same call
The offline tests are now parametrised over One case is deliberately excluded and pinned rather than supported: m=3, h=3. Rebased onto current On the other question: I have not seen @saxik13's |
separate files applicable to different number of phases, excitation (current vs. voltage), rotation direction, names of phases, ...
|
I have added the Ansys_transforms folder, which I use to create the output variables. It is in the original state, so it is independent of the Ansys environment, and it generates the .aoutvar file, which can be opened in Ansys. It is created as a general tool applicable to different existing Ansys models. So you can define the number of phases and harmonics, but also the excitation type (current vs. voltage), naming of the phases, rotation direction, inductance matrix (full or diagonal), or winding configuration, which defines the initial angle. When working on the new machine design, many of the features are not necessary. The initial angular position will be derived from the winding design directly - I am working on it now. |
Addresses #25 (the additive half — see "Not in this PR" below).
Why
The same five-phase Park/Clarke transform is written out by hand three times in the 5-phase anchor's output variables — once for flux linkage, once for input current, once for terminal voltage — off one pair of
cos/sintables. None of it needs the field solution; it is algebra on quantities the solve already produced (#25).What this adds — and it removes nothing
machine_design/transforms.pyto_dq/to_phases/electrical_angle, matching the Ansys convention exactly, including thesin(-h*(...))sign that makesqthe negative sine sumtests/test_transforms.py2/5scaling, theqsign, and both angle-unit pathstests/test_ansys_transforms.pyansys)CONTRIBUTING.md339 insertions, 0 deletions.
pytest42 passed / 5 deselected; ruff clean.Verified against a real solve
On bayes, AEDT 2024.2, 1 core: the Python transform reproduces Ansys's own dq output variables to 2.3e-15 (dq1) and 2.5e-16 (dq3) — floating-point exact, not within a tolerance. All four cross-checks pass.
Two things that verification turned up, both now recorded in the code:
1. Ansys reports
theta_elin degrees, not radians. The- piin its expression is evaluated as −180° in an angular context, sotheta_elcomes back as e.g.540(= 3π rad). The Ansys side is correct and internally consistent —theta_elis only ever used insidecos/sinas angle-minus-angle — but a Python consumer reading the raw number and callingnumpy.cosgets silent nonsense.electrical_angle()therefore takes an explicitdegrees=flag and always returns radians, with a test asserting the measured value3π. This is a second instance of the units class of problem from #16: Ansys is self-consistent, but its reported units surprise the consumer.2.
Flux_d1..q3are computed and then discarded.solution_expressionsrequestsFlux_e_*(excitation flux), notFlux_*— so the flux dq transforms never reach Python at present. Relevant to #25's removal list: they are the transforms we intend to keep in Ansys.Why the cross-check covers flux and voltage
Deliberate, and they have different lifetimes:
That is also why this PR comes before the removal: the equivalence proof is only executable beforehand.
Not in this PR
The removal itself — @saxik13's list in #25 (
Rstat,Lew,Vind_*,dI*_dt,V_A..V_E,V_AC..,Vterm_*,V_d1..V_q3: 30 output variables) plus trimmingsolution_expressions. That is a breaking change to whatextract_resultsreturns, so it wants its own PR once this is merged and consumers have migrated — justified by the numbers above.Per #25 I am keeping
I_d1..I_q3. They are redundant as a computation, but they are the only end-to-end check that the excitation Ansys applied is the one we commanded — which is exactly the failure mode #16 turned out to be. Worth reclassifying as an assertion rather than deleting.