diff --git a/machine_design/designs/computation.py b/machine_design/designs/computation.py index 5f8cfc0..33313ea 100644 --- a/machine_design/designs/computation.py +++ b/machine_design/designs/computation.py @@ -3,8 +3,7 @@ import numpy as np from ansys.aedt.core import Maxwell2d -from machine_design.generic.compute_initpos import compute_initpos -from machine_design.generic.winding import phase_groups +from machine_design.generic.winding import assign_slot_currents_to_aedt, compute_winding_layout from .geometry import GeometryBase from .reserved_variables import check_no_reserved_variable_names @@ -44,14 +43,10 @@ def extract_expression(solutions, expr: str) -> np.ndarray: def set_initpos(self) -> None: g = self.geometry Q = int(g.geom_params["SlotNumber"]) - self.InitPos = compute_initpos(Q, g.PolePairs, g.n_phases, belt_offset=g.belt_offset) + layout = compute_winding_layout(g.n_phases, Q, g.PolePairs, coil_pitch=int(g.wind_params["CoilPitch"]), layers=int(g.wind_params["Layers"])) + self.InitPos = (layout.phase_a_axis - 180) / g.PolePairs self.oper_params["InitPos"] = f"{self.InitPos}deg" - def compute_phase_groups(self): - g = self.geometry - Q = int(g.geom_params["SlotNumber"]) - return phase_groups(Q, g.PolePairs, g.n_phases, belt_offset=g.belt_offset) - def set_solution_expressions(self): self.solution_expressions = [ "Moving1.Position", @@ -74,21 +69,16 @@ def set_post_params(self): } def assign_phase_windings(self, m2d: Maxwell2d, phase_currents: list) -> None: - groups = self.compute_phase_groups() - for group in groups: - for coil_name, polarity in group: - m2d.assign_coil(assignment=[coil_name], conductors_number="Nc", polarity=polarity, name=f"CS_{coil_name}") - - for phase_name, current, group in zip(self.phases, phase_currents, groups): - m2d.assign_winding( - assignment=None, - winding_type="Current", - is_solid=False, - current=current, - parallel_branches="ParallelPaths", - name=f"Phase{phase_name}", - ) - m2d.add_winding_coils(assignment=f"Phase{phase_name}", coils=[f"CS_{coil_name}" for coil_name, _ in group]) + g = self.geometry + Q = int(g.geom_params["SlotNumber"]) + n = Q // (2 * g.PolePairs) + layers = int(g.wind_params["Layers"]) + layout = compute_winding_layout(g.n_phases, Q, g.PolePairs, coil_pitch=int(g.wind_params["CoilPitch"]), layers=layers) + layer_coils = [[f"Coil{i_layer}" if k == 0 else f"Coil{i_layer}_{k}" for k in range(n)] for i_layer in range(layers)] + coil_objects = layer_coils[0] + coil_objects_back = layer_coils[1] if layers == 2 else None + phase_currents_dict = dict(zip(self.phases, phase_currents)) + assign_slot_currents_to_aedt(m2d, coil_objects, layout, phase_currents_dict, coil_objects_back=coil_objects_back) def extract_phase_results(self, solutions): # SI units diff --git a/machine_design/generic/__init__.py b/machine_design/generic/__init__.py index a63bd58..ac80697 100644 --- a/machine_design/generic/__init__.py +++ b/machine_design/generic/__init__.py @@ -1,3 +1,2 @@ -from .compute_initpos import compute_initpos from .transforms import electrical_angle, to_dq, to_phases -from .winding import coil_name, phase_groups, sector_winding +from .winding import assign_slot_currents_to_aedt, compute_winding_layout diff --git a/machine_design/generic/compute_initpos.py b/machine_design/generic/compute_initpos.py deleted file mode 100644 index c7e4209..0000000 --- a/machine_design/generic/compute_initpos.py +++ /dev/null @@ -1,24 +0,0 @@ -import math - -from machine_design.generic.winding import sector_winding - - -def compute_initpos(Q: int, p: int, m: int, belt_offset: int): - """This function aims to compute the value of InitPos for those machines with d-axis - at 45deg. - Override this method if a different rotor generator places the d-axis elsewhere.""" - - out = sector_winding(Q, p, m, belt_offset) - xa = ya = 0.0 - for k, (phase_index, sign) in enumerate(out): - if phase_index != 0: # only need phase A - continue - theta_e_deg = (0.5 + k) * (360.0 * p / Q) - if sign > 0: - eff_deg = theta_e_deg - else: - eff_deg = theta_e_deg + 180.0 - xa += math.cos(math.radians(eff_deg)) - ya += math.sin(math.radians(eff_deg)) - gamma_e_deg = math.degrees(math.atan2(ya, xa)) - return round((gamma_e_deg - 90.0) / p, 6) diff --git a/machine_design/generic/winding.py b/machine_design/generic/winding.py index 70bb828..9a8b908 100644 --- a/machine_design/generic/winding.py +++ b/machine_design/generic/winding.py @@ -1,96 +1,297 @@ -"""Parametric stator winding-layout generator (pure algorithm, no AEDT). - -Produces the coil -> (phase, polarity) map for the one-pole, anti-periodic FEA -sector our machine models, for an arbitrary balanced integer-slot distributed -winding given (Q slots, p pole-pairs, m phases). It replaces the hardcoded -per-coil assignment in Design.assign_stator_coils / Design2.assign_stator_coils. - -Convention (reverse-engineered from, and validated to exactly reproduce, the -project's 40-slot/5-phase and 36-slot/3-phase windings): - - the FEA sector spans ONE pole, n = Q/(2p) slots = coils, with anti-periodic BC; - - q = Q/(2*p*m) slots per phase belt (must be a positive integer); - - coils are created in slot order: coil 0 = "Coil", coil k = "Coil_{k}"; - - belt index of coil k: b = (k + 1) // q (raw, half-slot-offset origin) - - phase index: ((m+1)//2 * b) mod m (standard (m+1)/2 progression) - - polarity: +1 if b even else -1 (alternating belts; the wrap - coil flips via anti-periodicity) +"""Winding layout of an m-phase AC stator winding for AEDT FEM models. + +Assigns a phase letter and polarity to each slot's coil side, for single- +or double-layer windings with integer or fractional slots per pole per +phase q = n/c (c must be coprime with the number of phases). Odd and even +phase counts are supported; an even-phase winding is treated as several +symmetrical sub-phase sets shifted against each other (e.g. six phases = +two 3-phase sets 30 el. deg apart). + +Besides the slot assignment, the layout provides: + - the electrical angle of each phase, + - the winding factor (pitch x distribution), with a warning below 0.9, + - p2_min_fem, the minimum pole count of the FEM sector (odd values mean + an antiperiodic boundary), + - the electrical axis of phase A in the model, + - the coil pitch, auto-selected when not given. + +assign_slot_currents_to_aedt then creates AEDT coils and current windings +from a layout. """ +import warnings +from dataclasses import dataclass +from fractions import Fraction +from math import ceil, gcd, pi, sin + + +@dataclass(frozen=True) +class WindingLayout: + coil_pitch: int + phase: list[str] + polarity: list[int] + phase_order: list[str] + winding_factor: float + phase_angles: dict[str, float] # electrical angle [deg] of each phase, e.g. {"A": 0.0, "B": -30.0, ...} + p2_min_fem: int # minimum pole count of the FEM sector (odd allowed - antiperiodic boundary) + phase_a_axis: float # electrical axis [deg, 0..180) of phase A in the model + phase_back: list[str] | None = None + polarity_back: list[int] | None = None + + +def _phase_axis_tables(phases: int): + """ + Returns (phase_letters, phase_signs, phase_angles): the phase letter and + +-1 marker for each of the `phases` phase-group positions used by the + main assignment loop, fixed by sorting all 2*phases physical+mathematical + phase axes by electrical angle (descending) and keeping the first + `phases`; phase_angles maps each phase letter to its electrical angle. + + An even phase count m is treated as x symmetrical (m/x)-phase sets, x + being the largest power of two dividing m, with neighbouring sets + shifted by 360/(2*m) electrical degrees. E.g. six phases are two + symmetrical 3-phase sets (ACE and BDF) shifted by 30 degrees. + """ + if phases % 2 == 0: # even phases + phase_sets = 1 + reduced_phases = phases + gcd_value = 2 + while gcd_value == 2: + gcd_value = gcd(reduced_phases, 2) + phase_sets *= gcd_value + reduced_phases //= gcd_value + + phase_shift_step = -360.0 / reduced_phases + phase_angles_base = [i * phase_shift_step for i in range(reduced_phases)] + phase_angle_matrix = [] + for set_index in range(phase_sets): + set_shift = -360.0 / (2 * phases) * set_index + phase_angle_matrix.append([v + set_shift for v in phase_angles_base]) + # Flatten column-major (set index varies fastest). + phase_angles = [phase_angle_matrix[row][col] for col in range(reduced_phases) for row in range(phase_sets)] + phase_angles.sort(reverse=True) + else: # even phases + phase_shift_step = -360.0 / phases + phase_angles = [i * phase_shift_step for i in range(phases)] + + # phase_angles[i] is the axis of phase chr(65 + i) (A, B, C, ...) + phase_angle_by_letter = {chr(65 + i): angle + 0.0 for i, angle in enumerate(phase_angles)} + + phase_angles_back = [] + for angle in phase_angles: + angle_back = angle + 180.0 + if angle_back > 0: + angle_back -= 360.0 + phase_angles_back.append(angle_back) + + phase_angles_all = phase_angles + phase_angles_back + phase_signs = [1] * phases + [-1] * phases + phase_letter_codes = [chr(65 + i) for i in range(phases)] * 2 + + order = sorted(range(2 * phases), key=lambda i: phase_angles_all[i], reverse=True) + phase_letters_sorted = [phase_letter_codes[i] for i in order] + phase_signs_sorted = [phase_signs[i] for i in order] + + return phase_letters_sorted[:phases], phase_signs_sorted[:phases], phase_angle_by_letter + + +def compute_winding_layout( + phases: int, + slots: int, + pole_pairs: int, + coil_pitch: int | None = None, + layers: int = 1, +) -> WindingLayout: + """Compute per-slot phase letter and polarity for an m-phase AC winding. + + `coil_pitch` is given in slots; None or 0 auto-selects the pitch closest + to (2m-1)/(2m) of the pole pitch (odd for a single layer). For + layers == 1, each slot holds one coil side; `phase_back`/`polarity_back` + are populated only for layers == 2 and describe the second (inner/bottom) + radial coil side per slot. + """ + if layers not in (1, 2): + raise ValueError("layers must be 1 or 2") -def coil_name(k: int) -> str: - """AEDT object name for the k-th duplicated coil (0-based).""" - return "Coil" if k == 0 else f"Coil_{k}" + pole_count = 2 * pole_pairs + if slots % (phases) != 0: + raise ValueError(f"slots ({slots}) must be divisible by number of phases ({phases})") + slots_ppp = Fraction(slots, pole_count * phases) # q, as an exact fraction n/c + slots_ppp_numer = slots_ppp.numerator # n + slots_ppp_denom = slots_ppp.denominator # c + if gcd(slots_ppp_denom, phases) != 1: + raise ValueError(f"c ({slots_ppp_denom}) and the number of phases ({phases}) must be coprime for a symmetric winding") + pole_pitch_slots = slots / pole_count # t_pd + if not coil_pitch: + optimal_pitch_ratio = (2 * phases - 1) / (2 * phases) + optimal_coil_pitch = optimal_pitch_ratio * pole_pitch_slots + coil_pitch = round(optimal_coil_pitch) + if layers == 1 and coil_pitch % 2 == 0: + coil_pitch = coil_pitch - 1 if coil_pitch > optimal_coil_pitch else coil_pitch + 1 + if layers == 1 and coil_pitch % 2 == 0: + raise ValueError(f"single-layer winding requires an odd coil pitch, got {coil_pitch}") -def sector_winding(Q: int, p: int, m: int, belt_offset: int = 1): - """Return a list (length n = Q/(2p)) of (phase_index 0..m-1, sign +/-1), - one entry per sector coil in slot/creation order. + # effective_n (coil sides per phase group, used for the distribution + # factor) is derived from n, not q; it and c together fix p2_min - the minimum pole count for which the winding + # pattern closes periodically. The model's actual pole count must be an + # integer multiple of p2_min. + if layers == 2: + effective_n = slots_ppp_numer + p2_min = 2 * slots_ppp_denom if slots_ppp_denom % 2 == 1 else slots_ppp_denom + p2_min_fem = slots_ppp_denom + elif slots_ppp_numer % 2 == 0: + effective_n = slots_ppp_numer // 2 + p2_min = 2 * slots_ppp_denom if slots_ppp_denom % 2 == 1 else slots_ppp_denom + p2_min_fem = slots_ppp_denom + else: + effective_n = slots_ppp_numer + p2_min = 2 * slots_ppp_denom + p2_min_fem = slots_ppp_denom if coil_pitch == pole_pitch_slots else 2 * slots_ppp_denom + if pole_count % p2_min != 0: + raise ValueError(f"pole count ({pole_count}) must be a multiple of the minimum pole count {p2_min} required for this winding (phases={phases}, slots={slots}, layers={layers}) to close periodically") - belt_offset shifts the belt origin (a pure spatial rotation of the winding, - immaterial to performance, absorbed by the rotor-alignment / current angle): - - belt_offset=1 -> PhaseA centred on the d-axis with an anti-periodic wrap; - reproduces the project's 5-phase (40-slot) winding. Default / preferred. - - belt_offset=0 -> belts start at slot 0; reproduces the legacy 3-phase - (36-slot) base winding. - New machines should use the default (1) and align the dq reference to it.""" - if Q % (2 * p * m) != 0: - raise ValueError(f"non-integer slots/pole/phase: Q={Q}, 2*p*m={2 * p * m} (q=Q/(2pm) must be a positive integer for this winding)") - n = Q // (2 * p) # coils in the one-pole sector - q = Q // (2 * p * m) # slots per belt - step = (m + 1) // 2 - out = [] - for k in range(n): - b = (k + belt_offset) // q - out.append(((step * b) % m, 1 if b % 2 == 0 else -1)) - return out + phase_letters, phase_signs, phase_angles = _phase_axis_tables(phases) + single_layer_flag = layers % 2 # 1 = single layer (needs gap-fill), 0 = double layer + slot_step = 1 + single_layer_flag -def phase_groups(Q: int, p: int, m: int, belt_offset: int = 1): - """Return m lists; phase j -> [(coil_name, polarity_str), ...] for driving - assign_coil / add_winding_coils generically.""" - groups = [[] for _ in range(m)] - for k, (ph, sg) in enumerate(sector_winding(Q, p, m, belt_offset)): - groups[ph].append((coil_name(k), "Positive" if sg > 0 else "Negative")) - return groups + phase: list[str | None] = [None] * slots + polarity: list[int | None] = [None] * slots + front_slot_indices: list[int] = [] + + # cell_index walks the technological-scheme grid (step slot_step*c); + # slot_index walks the physical slots (step slot_step) - the two only + # stay in lockstep when c == 1. + cell_step = slot_step * slots_ppp_denom + pole_row = 1 + sign = 1 + cell_index = 1 + slot_index = 0 + while cell_index <= pole_count * phases * slots_ppp_numer: + while cell_index > phases * slots_ppp_numer * pole_row: + pole_row += 1 + sign = -sign + phase_group = ceil((cell_index - (pole_row - 1) * phases * slots_ppp_numer) / slots_ppp_numer) # 1..phases + phase[slot_index] = phase_letters[phase_group - 1] + polarity[slot_index] = sign * phase_signs[phase_group - 1] + front_slot_indices.append(slot_index) + slot_index += slot_step + cell_index += cell_step + + phase_back: list[str] | None = None + polarity_back: list[int] | None = None + + if layers == 1: + # For a single layer the loop above fills every other slot only; + # the remaining slots are the back coil sides, related to the front + # ones by the coil pitch: back[s] = -front[(s - coil_pitch) mod slots]. + for slot in range(slots): + if phase[slot] is None: + source = (slot - coil_pitch) % slots + phase[slot] = phase[source] + polarity[slot] = -polarity[source] + else: + phase_back = [None] * slots + polarity_back = [None] * slots + for slot in range(slots): + source = (slot - coil_pitch) % slots + phase_back[slot] = phase[source] + polarity_back[slot] = -polarity[source] + + pitch_ratio = coil_pitch / pole_pitch_slots + pitch_factor = sin(pitch_ratio * pi / 2) + distribution_factor = sin(pi / (2 * phases)) / (effective_n * sin(pi / (2 * phases * effective_n))) + winding_factor = pitch_factor * distribution_factor + if winding_factor < 0.9: + warnings.warn(f"winding factor is low: {winding_factor:.3g} (< 0.9)") + + phase_order = [chr(65 + i) for i in range(phases)] + + # Phase A axis: mean (mod 180) electrical angle of phase A's front coil + # sides, plus half the coil pitch (front side -> coil axis) and half a + # slot pitch (index 0 sits on a tooth, not a slot center - the base coil + # rectangle is rotated by half a slot pitch before being duplicated + # around the machine). + slot_pitch_el = 360.0 * pole_pairs / slots + a_angles = [(i * slot_pitch_el) % 180.0 for i in front_slot_indices if phase[i] == "A"] + if not a_angles: + raise ValueError("phase 'A' has no front coil side in this winding") + front_a_axis = sum(a_angles) / len(a_angles) + phase_a_axis = (front_a_axis + coil_pitch * slot_pitch_el / 2.0 + slot_pitch_el / 2.0) % 180.0 + + return WindingLayout( + coil_pitch=coil_pitch, + phase=phase, + polarity=polarity, + phase_order=phase_order, + winding_factor=winding_factor, + phase_angles=phase_angles, + p2_min_fem=p2_min_fem, + phase_a_axis=phase_a_axis, + phase_back=phase_back, + polarity_back=polarity_back, + ) + + +def assign_slot_currents_to_aedt( # for second layer, use layout.phase_back, andlayout.polarity_back + m2d, + coil_objects: list[str], + layout: WindingLayout, + phase_currents: dict[str, str], + coil_objects_back=None, + turns_var: str = "Nc", + parallel_paths_var: str = "ParallelPaths", +) -> dict[str, str]: + """Assign AEDT coils and windings from a WindingLayout. + + Replaces the hand-written assign_coil/assign_winding/add_winding_coils + blocks. `coil_objects` must be in the same slot order as + `layout.phase`/`layout.polarity` (i.e. modeler.get_objects_w_string(...) + right after duplicate_around_axis). Returns {phase_letter: winding_name} + for the windings that were created. + """ + coil_names_by_phase: dict[str, list[str]] = {p: [] for p in layout.phase_order} + + for i, obj in enumerate(coil_objects): + letter = layout.phase[i] + polarity = "Positive" if layout.polarity[i] > 0 else "Negative" + cs_name = f"CS{i + 1}" + m2d.assign_coil(assignment=[obj], conductors_number=turns_var, polarity=polarity, name=cs_name) + coil_names_by_phase[letter].append(cs_name) + + if coil_objects_back is not None: + for i, obj in enumerate(coil_objects_back): + letter = layout.phase_back[i] + polarity = "Positive" if layout.polarity_back[i] > 0 else "Negative" + cs_name = f"CSB{i + 1}" # CSB means CS Back + m2d.assign_coil(assignment=[obj], conductors_number=turns_var, polarity=polarity, name=cs_name) + coil_names_by_phase[letter].append(cs_name) + + winding_names: dict[str, str] = {} + for letter, cs_list in coil_names_by_phase.items(): + if not cs_list or letter not in phase_currents: + continue + winding_name = f"Phase{letter}" + m2d.assign_winding( + assignment=None, + winding_type="Current", + is_solid=False, + current=phase_currents[letter], + parallel_branches=parallel_paths_var, + name=winding_name, + ) + m2d.add_winding_coils(assignment=winding_name, coils=cs_list) + winding_names[letter] = winding_name + + return winding_names if __name__ == "__main__": - PHASE = "ABCDEFG" - - # --- validation: must reproduce the existing hardcoded windings exactly --- - def asmap(Q, p, m, off): - g = {} - for k, (ph, sg) in enumerate(sector_winding(Q, p, m, off)): - g.setdefault(PHASE[ph], set()).add((k, sg)) - return g - - EXPECT_5 = { # design2.assign_stator_coils (CS_i -> Coil_{i-1} -> slot i-1) - "A": {(0, 1), (9, -1)}, - "B": {(3, 1), (4, 1)}, - "C": {(7, 1), (8, 1)}, - "D": {(1, -1), (2, -1)}, - "E": {(5, -1), (6, -1)}, - } - EXPECT_3 = { # design.assign_stator_coils (PhaseA=CS1-3, B=CS7-9, C=CS4-6) - "A": {(0, 1), (1, 1), (2, 1)}, - "B": {(6, 1), (7, 1), (8, 1)}, - "C": {(3, -1), (4, -1), (5, -1)}, - } - assert asmap(40, 2, 5, 1) == EXPECT_5, "5-phase (offset 1) mismatch" - assert asmap(36, 2, 3, 0) == EXPECT_3, "3-phase (offset 0) mismatch" - print("OK reproduces BOTH hardcoded windings exactly: 5-phase 40-slot (offset 1), 3-phase 36-slot (offset 0)") - - def show(Q, p, m): - lay = sector_winding(Q, p, m) - bins = {} - for k, (ph, sg) in enumerate(lay): - bins.setdefault(PHASE[ph], []).append(f"{coil_name(k)}{'+' if sg > 0 else '-'}") - q = Q // (2 * p * m) - print(f"\n(Q={Q}, p={p}, m={m}) sector coils={len(lay)} q={q}") - for ph in sorted(bins): - print(f" Phase {ph}: {bins[ph]}") - - show(40, 2, 5) # current 5-phase - show(36, 2, 3) # current 3-phase - show(60, 2, 3) # common-stator target, 3-phase - show(60, 2, 5) # common-stator target, 5-phase + layout_6ph = compute_winding_layout(phases=6, slots=48, pole_pairs=5, coil_pitch=5, layers=1) + layout_6ph_v2 = compute_winding_layout(phases=6, slots=48, pole_pairs=2, coil_pitch=11, layers=1) + + layout_3ph = compute_winding_layout(phases=3, slots=6, pole_pairs=2, coil_pitch=1, layers=2) + layout_5ph = compute_winding_layout(phases=5, slots=40, pole_pairs=2, coil_pitch=9, layers=1) + + print("All self-tests passed.") diff --git a/motors/synrm_3f_36s.py b/motors/synrm_3f_36s.py index 7228355..7b888ea 100644 --- a/motors/synrm_3f_36s.py +++ b/motors/synrm_3f_36s.py @@ -43,13 +43,12 @@ def set_winds_params(self): "CoilPitch": "9", # coil pitch in slots "SlotLiner": "0.3mm", "SpaceLayers": "0.2mm", - "Nc": "68", # turns per coil + "Nc": "68/Layers", # turns per coil } def set_mod_params(self): self.PolePairs = 2 self.n_phases = 3 - self.belt_offset = 0 self.mod_params = { "Poles": f"2*{self.PolePairs}", "ModelLength": "85mm", @@ -143,15 +142,18 @@ def _build_stator_coils(self, m2d: Maxwell2d): modeler = m2d.modeler assert isinstance(modeler, Modeler2D) - coil_id = modeler.create_rectangle( - origin=["DiaStatorGap/2+Hs0+Hs1+SlotLiner", "-(Bs1/2-SlotLiner)", 0], - sizes=["(Hs2+Rs/2-2*SlotLiner)/Layers-(Layers-1)*SpaceLayers/2", "Bs1-2*SlotLiner", 0], - name="Coil", - material="copper", - ) - modeler.rotate(assignment=coil_id, axis="Z", angle="360deg/SlotNumber/2") - coil_id.duplicate_around_axis(axis="Z", angle="360deg/SlotNumber", clones="SlotNumber/Poles", create_new_objects=True) - id_coils = modeler.get_objects_w_string(string_name="Coil", case_sensitive=True) + id_coils = [] + for i_layer in range(int(self.wind_params["Layers"])): + coil_id = modeler.create_rectangle( + origin=[f"DiaStatorGap/2+Hs0+Hs1+SlotLiner+{i_layer}*((Hs2+Rs/2-2*SlotLiner-(Layers-1)*SpaceLayers)/Layers+SpaceLayers)", "-(Bs1/2-SlotLiner)", 0], + sizes=["(Hs2+Rs/2-2*SlotLiner-(Layers-1)*SpaceLayers)/Layers", "Bs1-2*SlotLiner", 0], + name=f"Coil{i_layer}", + material="copper", + ) + + modeler.rotate(assignment=coil_id, axis="Z", angle="360deg/SlotNumber/2") + coil_id.duplicate_around_axis(axis="Z", angle="360deg/SlotNumber", clones="SlotNumber/Poles", create_new_objects=True) + id_coils += modeler.get_objects_w_string(string_name=f"Coil{i_layer}", case_sensitive=True) return id_coils diff --git a/motors/synrm_5f_40s.py b/motors/synrm_5f_40s.py index 8776501..596dd76 100644 --- a/motors/synrm_5f_40s.py +++ b/motors/synrm_5f_40s.py @@ -26,12 +26,11 @@ def set_slot_params(self): def set_winds_params(self): super().set_winds_params() - self.wind_params["Nc"] = "113" + self.wind_params["Nc"] = "113/Layers" def set_mod_params(self): super().set_mod_params() self.n_phases = 5 - self.belt_offset = 1 class Computation(ComputationBase): diff --git a/tests/test_synrm_3f_36s.py b/tests/test_synrm_3f_36s.py index 95ffa38..98bf9c9 100644 --- a/tests/test_synrm_3f_36s.py +++ b/tests/test_synrm_3f_36s.py @@ -57,7 +57,7 @@ def test_wind_params(geometry): "CoilPitch": "9", "SlotLiner": "0.3mm", "SpaceLayers": "0.2mm", - "Nc": "68", + "Nc": "68/Layers", } diff --git a/tests/test_synrm_5f_40s.py b/tests/test_synrm_5f_40s.py index dbfe673..ad2209d 100644 --- a/tests/test_synrm_5f_40s.py +++ b/tests/test_synrm_5f_40s.py @@ -39,7 +39,7 @@ def test_slot_params_overrides_bs1_bs2_setangle_only(base_geometry, geometry2): def test_wind_params_overrides_nc_only(base_geometry, geometry2): expected = dict(base_geometry.wind_params) - expected["Nc"] = "113" + expected["Nc"] = "113/Layers" assert geometry2.wind_params == expected