From d8f96709534508347fc7123967a49ace7a988601 Mon Sep 17 00:00:00 2001 From: SebGue Date: Thu, 24 Apr 2025 15:52:08 +0200 Subject: [PATCH 1/9] [CC] add missing lam. side lines (sym!=1 with notches) --- .../Methods/Machine/Lamination/build_yoke_side_line.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pyleecan/Methods/Machine/Lamination/build_yoke_side_line.py b/pyleecan/Methods/Machine/Lamination/build_yoke_side_line.py index e29bdd1f5..2921e0968 100644 --- a/pyleecan/Methods/Machine/Lamination/build_yoke_side_line.py +++ b/pyleecan/Methods/Machine/Lamination/build_yoke_side_line.py @@ -106,6 +106,13 @@ def merge_line_list(Z1, Z2, label, inter_list): ) ii += 1 line.prop_dict[BOUNDARY_PROP_LAB] = label + "-" + str(ii) + line_list.append( + Segment( + line.get_begin(), + line.get_end(), + prop_dict={BOUNDARY_PROP_LAB: label + "-" + str(ii)}, + ) + ) ii += 1 Zb = line.get_end() # Add last line (or Z1 to Z2 if no intersection) From 74ffbfc55b7f444d00dac7f7db7c89ddebf28e3a Mon Sep 17 00:00:00 2001 From: SebGue Date: Thu, 8 May 2025 10:26:57 +0200 Subject: [PATCH 2/9] [CC] VSCode: launch.json --- .vscode/launch.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 472bd0c56..009dfd414 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "configurations": [ { "name": "Python: Current File (Integrated Terminal)", - "type": "python", + "type": "debugpy", "request": "launch", "program": "${file}", "console": "integratedTerminal", @@ -17,14 +17,14 @@ }, { "name": "Python: Code gen (GUI Ui only)", - "type": "python", + "type": "debugpy", "request": "launch", "program": "${workspaceFolder}/pyleecan/Generator/run_generate_GUI.py", "console": "integratedTerminal" }, { "name": "Python: Code gen (GUI resources only)", - "type": "python", + "type": "debugpy", "request": "launch", "program": "${workspaceFolder}/pyleecan/Generator/run_generate_GUI_resources.py", "console": "integratedTerminal", @@ -34,7 +34,7 @@ }, { "name": "Python: Code gen (Classes from csv)", - "type": "python", + "type": "debugpy", "request": "launch", "program": "${workspaceFolder}/pyleecan/Generator/run_generate_classes.py", "console": "integratedTerminal", @@ -45,7 +45,7 @@ }, { "name": "Python: Run GUI", - "type": "python", + "type": "debugpy", "request": "launch", "program": "${workspaceFolder}/pyleecan/run_GUI.py", "console": "integratedTerminal", @@ -56,7 +56,7 @@ }, { "name": "Python: Run class gen GUI", - "type": "python", + "type": "debugpy", "request": "launch", "program": "${workspaceFolder}/pyleecan/Generator/run_class_generator_GUI.py", "console": "integratedTerminal", @@ -67,7 +67,7 @@ }, { "name": "Python: Run script", - "type": "python", + "type": "debugpy", "request": "launch", "program": "${workspaceFolder}/script.py", "console": "integratedTerminal", @@ -78,7 +78,7 @@ }, { "name": "Python: Current File (External Terminal)", - "type": "python", + "type": "debugpy", "request": "launch", "program": "${file}", "console": "externalTerminal" From 2e1f607c969e06ab3d5f58e6625d30699ad196b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=BCnther?= Date: Fri, 20 Jun 2025 13:41:00 +0200 Subject: [PATCH 3/9] [CO] add test for bore and notch --- Tests/Methods/Machine/test_bore_and_notch.py | 65 ++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Tests/Methods/Machine/test_bore_and_notch.py diff --git a/Tests/Methods/Machine/test_bore_and_notch.py b/Tests/Methods/Machine/test_bore_and_notch.py new file mode 100644 index 000000000..99147be5a --- /dev/null +++ b/Tests/Methods/Machine/test_bore_and_notch.py @@ -0,0 +1,65 @@ +from os.path import join + +import matplotlib.pyplot as plt +import pytest +from numpy import pi +from pyleecan.Classes.NotchEvenDist import NotchEvenDist +from pyleecan.Classes.BoreSinePole import BoreSinePole +from pyleecan.Classes.BoreFlower import BoreFlower +from pyleecan.Classes.SlotCirc import SlotCirc +from pyleecan.Classes.SlotW26 import SlotW26 +from pyleecan.definitions import DATA_DIR +from pyleecan.Functions.load import load + +mm = 1e-3 + +@pytest.mark.IPMSM +@pytest.mark.SCIM +def test_bore_and_notch(is_show_fig=False): + """Validation of rotor and stator notches""" + + # Load machines + Toyota_Prius = load(join(DATA_DIR, "Machine", "Toyota_Prius.json")) + Audi_eTron = load(join(DATA_DIR, "Machine", "Audi_eTron.json")) + + # Add notches to Toyota_Prius + p = Toyota_Prius.get_pole_pair_number() + + NBs = SlotCirc(Zs=24, W0=4 * mm, H0=1 * mm) + NBq = SlotCirc(Zs=2 * p, W0=4 * mm, H0=1 * mm) + NBdq = SlotCirc(Zs=2 * p, W0=6 * mm, H0=1 * mm) + NCirc1 = SlotCirc(Zs=2 * p, W0=8 * mm, H0=2 * mm) + NSlowW26 = SlotW26(Zs=2 * p, W0=1*mm, H0=2*mm, H1=0, R1=3*mm, R2=3*mm) + NSlowW26w = SlotW26(Zs=2 * p, W0=9*mm, H0=2*mm, H1=0, R1=5*mm, R2=5*mm) # wide slot + a0 = 0.25 + + Toyota_Prius.rotor.notch = [ + # NotchEvenDist(alpha=0, notch_shape=NBq), + # NotchEvenDist(alpha=0.5 * pi / p + a0, notch_shape=NBdq), + # NotchEvenDist(alpha=0.5 * pi / p - a0, notch_shape=NBdq), + # NotchEvenDist(alpha=0.5 * pi / p, notch_shape=NCirc1), + NotchEvenDist(alpha=0.5 * pi / p, notch_shape=NSlowW26w), + ] + delta_d = Toyota_Prius.stator.Rint - Toyota_Prius.rotor.Rext + Toyota_Prius.rotor.bore = BoreSinePole(N=8, delta_d=delta_d, delta_q=5*mm, W0=50*mm) + + Toyota_Prius.plot(sym=8, is_show_fig=is_show_fig) + Toyota_Prius.plot(is_show_fig=is_show_fig) + + # Add notches to Audi_eTron + NBs = SlotCirc(Zs=16, W0=0.001, H0=0.0005) + NBr = SlotCirc(Zs=29, W0=0.001, H0=0.0005) + + Audi_eTron.stator.notch = [NotchEvenDist(alpha=0, notch_shape=NBs)] + Audi_eTron.rotor.notch = [NotchEvenDist(alpha=0, notch_shape=NBr)] + + # Audi_eTron.plot(sym=2, is_show_fig=is_show_fig) + # Audi_eTron.plot(is_show_fig=is_show_fig) + + return Toyota_Prius, Audi_eTron + + +if __name__ == "__main__": + Toyota_Prius, Audi_eTron = test_bore_and_notch(is_show_fig=True) + plt.show() + print("Done") From 9bbaae77c5ddb07d1a0763963ef590cf192446f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=BCnther?= Date: Fri, 20 Jun 2025 13:42:19 +0200 Subject: [PATCH 4/9] [WiP] merge slot intersect --- .../Machine/Bore/merge_slot_intersect.py | 116 ++++++++++++------ 1 file changed, 76 insertions(+), 40 deletions(-) diff --git a/pyleecan/Methods/Machine/Bore/merge_slot_intersect.py b/pyleecan/Methods/Machine/Bore/merge_slot_intersect.py index 9649954e2..ff9417865 100644 --- a/pyleecan/Methods/Machine/Bore/merge_slot_intersect.py +++ b/pyleecan/Methods/Machine/Bore/merge_slot_intersect.py @@ -23,10 +23,17 @@ def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): line_list : list List of lines needed to draw the radius """ - # Get all Radius lines (0 to 2*pi) radius_lines = self.get_bore_line() + # fig, ax = None, None + # for desc in radius_desc_list: + # fig, ax = _plot_lines(desc['lines'], fig=fig, ax=ax, color="b") + # fig, ax = _plot_lines(radius_lines, fig=fig, ax=ax, color="gray") + # ax.axis('equal') + # fig.show() + + # Update begin and end angle if Radius (next step already cut lines) if sym != 1 and radius_desc_list[0]["label"] == "Radius": radius_desc_list[0]["begin_angle"] = 0 @@ -40,21 +47,6 @@ def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): radius_lines, desc_dict["begin_angle"], desc_dict["end_angle"] ) - # # Check that the Radius lines are correct - # for ii, desc_dict in enumerate(radius_desc_list): - # if desc_dict["label"] == "Radius": - # print(ii) - # print( - # str(desc_dict["begin_angle"]) - # + " and " - # + str(angle(desc_dict["lines"][0].get_begin()) % (2 * pi)) - # ) - # print( - # str(desc_dict["end_angle"]) - # + " and " - # + str(angle(desc_dict["lines"][-1].get_end()) % (2 * pi)) - # ) - # If slot/notch are coliding with sym lines => Cut if sym != 1: # Cut first desc (if needed) @@ -86,6 +78,7 @@ def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): line.prop_dict.update(prop_dict) line_list.extend(desc_dict["lines"]) else: # Intersect and add slot/notch lines + # fig, ax = _plot_lines(desc_dict['lines'], is_show=True) # Define First cutting line # rad_line = radius_desc_list[ii - 1]["lines"][-1] op = desc_dict["end_angle"] - desc_dict["begin_angle"] @@ -95,19 +88,25 @@ def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): desc_dict["begin_angle"] - op / 4, desc_dict["begin_angle"] + op / 4, ) - # Find first line to intersect with cutting line - for jj in range(len(desc_dict["lines"])): - inter_list = desc_dict["lines"][jj].intersect_obj( - rad_line_list[-1], is_on_line=True - ) - if len(inter_list) > 0: + # Find first intersection between any line in rad_line_list + # and any line in desc_dict["lines"] + for cutting_line in rad_line_list[::-1]: + for jj, line in enumerate(desc_dict["lines"]): + inter_list = line.intersect_obj(cutting_line, is_on_line=True) + if inter_list: + break + if inter_list: break - if jj < len(desc_dict["lines"]) - 1: - # Slot/notch was cut => Replace lines by cut ones - desc_dict["lines"] = desc_dict["lines"][ - jj: - ] # Keep all lines after cut - # Update lines to start/end at cutting point + + # fig, ax = _plot_lines(desc_dict['lines'], is_show=False) + # fig, ax = _plot_lines([rad_line_list[-1]], color="r", fig=fig, ax=ax, is_show=True) + # fig, ax = _plot_lines([cutting_line], color="b", fig=fig, ax=ax, is_show=False) + # fig, ax = _plot_lines(line_list, color="g", linestyle="-.", fig=fig, ax=ax, is_show=True) + + if inter_list: + # slot/notch was cut => replace slot/notch lines by cut ones, i.e. + # keep all lines after the cut and update to start at cutting point + desc_dict["lines"] = desc_dict["lines"][jj:] desc_dict["lines"][0].split_point(inter_list[0], is_begin=False) if len(line_list) == 0: # Slot/notch on Ox radius_desc_list[-1]["lines"][-1].split_point( @@ -115,7 +114,7 @@ def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): ) else: line_list[-1].split_point(inter_list[0], is_begin=True) - else: # The slot is above the shape => Use shape lines + else: # the slot is above the bore shape => use bore shape lines desc_dict["lines"] = cut_lines_between_angles( radius_lines, desc_dict["begin_angle"], desc_dict["end_angle"] ) @@ -126,7 +125,13 @@ def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): line.prop_dict = dict() line.prop_dict.update(prop_dict) line_list.extend(desc_dict["lines"]) + # fig, ax = _plot_lines(radius_lines) + # fig, ax = _plot_lines(desc_dict["lines"], fig=fig, ax=ax, color="b") + # fig, ax = _plot_lines([rad_line_list[-1]], fig=fig, ax=ax, color="r") + # fig, ax = _plot_point(rad_line_list[-1].get_begin(), fig=fig, ax=ax, color="r", marker=".") + # fig, ax = _plot_point(rad_line_list[-1].get_end(), fig=fig, ax=ax, color="r", marker=".", is_show=True) continue # No need to cut the other side + # Second cut if not (ii == len(radius_desc_list) - 1 and sym != 1): # No second cut for notch on sym line @@ -135,19 +140,21 @@ def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): desc_dict["end_angle"] - op / 4, desc_dict["end_angle"] + op / 4, ) - for jj in range(len(desc_dict["lines"])): - inter_list = desc_dict["lines"][-(jj + 1)].intersect_obj( - rad_line_list[0], is_on_line=True - ) - if len(inter_list) > 0: + + for cutting_line in rad_line_list: + for jj, line in enumerate(desc_dict["lines"][::-1]): + inter_list = line.intersect_obj(cutting_line, is_on_line=True) + if inter_list: + break + if inter_list: break - if jj < len(desc_dict["lines"]): + + if inter_list: # Slot/notch was cut => Replace lines by cut ones - if jj != 0: # Keep all the lines if last line is cut - desc_dict["lines"] = desc_dict["lines"][ - :-jj - ] # Keep all lines before cut - # Update lines to start/end at cutting point + if jj != 0: # Keep all the lines if last line is cut + # keep all lines before cut + desc_dict["lines"] = desc_dict["lines"][:-jj] + # update lines to end at cutting point desc_dict["lines"][-1].split_point(inter_list[0], is_begin=True) radius_desc_list[ii + 1]["lines"][0].split_point( inter_list[0], is_begin=False @@ -155,3 +162,32 @@ def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): # Add slot/notch lines to final list line_list.extend(desc_dict["lines"]) return line_list + + +def _plot_lines( + lines, color="k", linestyle="-", linewidth=1, fig=None, ax=None, is_show=False + ): + + # fig, ax = None, None + for line in lines: + fig, ax = line.plot( + fig=fig, ax=ax, color=color, linewidth=linewidth, linestyle=linestyle + ) + + if is_show: + ax.axis('equal') + fig.show() + + return fig, ax + +def _plot_point( + point, color="k", marker="o", markersize=10, fig=None, ax=None, is_show=False + ): + + ax.plot(point.real, point.imag, marker=marker, markersize=markersize, color=color) + + if is_show: + ax.axis('equal') + fig.show() + + return fig, ax From fdac4a35b4d6baa23a874e91240e8dd6682a3088 Mon Sep 17 00:00:00 2001 From: SebGue Date: Tue, 29 Jul 2025 14:29:15 +0200 Subject: [PATCH 5/9] [WiP] fix cut lines bug --- Tests/Methods/Machine/test_bore_and_notch.py | 4 +- .../Geometry/cut_lines_between_angle.py | 62 +++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/Tests/Methods/Machine/test_bore_and_notch.py b/Tests/Methods/Machine/test_bore_and_notch.py index 99147be5a..2b655baeb 100644 --- a/Tests/Methods/Machine/test_bore_and_notch.py +++ b/Tests/Methods/Machine/test_bore_and_notch.py @@ -20,7 +20,7 @@ def test_bore_and_notch(is_show_fig=False): # Load machines Toyota_Prius = load(join(DATA_DIR, "Machine", "Toyota_Prius.json")) - Audi_eTron = load(join(DATA_DIR, "Machine", "Audi_eTron.json")) + Audi_eTron = load(join(DATA_DIR, "Machine", "AUDI_eTron.json")) # Add notches to Toyota_Prius p = Toyota_Prius.get_pole_pair_number() @@ -43,7 +43,7 @@ def test_bore_and_notch(is_show_fig=False): delta_d = Toyota_Prius.stator.Rint - Toyota_Prius.rotor.Rext Toyota_Prius.rotor.bore = BoreSinePole(N=8, delta_d=delta_d, delta_q=5*mm, W0=50*mm) - Toyota_Prius.plot(sym=8, is_show_fig=is_show_fig) + # Toyota_Prius.plot(sym=8, is_show_fig=is_show_fig) Toyota_Prius.plot(is_show_fig=is_show_fig) # Add notches to Audi_eTron diff --git a/pyleecan/Functions/Geometry/cut_lines_between_angle.py b/pyleecan/Functions/Geometry/cut_lines_between_angle.py index 51d7a4e3f..9f68dc259 100644 --- a/pyleecan/Functions/Geometry/cut_lines_between_angle.py +++ b/pyleecan/Functions/Geometry/cut_lines_between_angle.py @@ -20,6 +20,16 @@ def cut_lines_between_angles(line_list, begin_angle, end_angle): cut_lines : [Line] Cut lines between the two angles """ + # normalize angles according to numpy.angle range + begin_angle = angle(exp(1j * begin_angle)) + end_angle = angle(exp(1j * end_angle)) + mean_angle = angle(exp(1j * begin_angle) + exp(1j * end_angle)) + + # rotate list in case first/last line is in between begin and end angle + # first copy list + sorted_list = [line for line in line_list] + # rotate until first line is before begin angle + first_cut = list() cut_lines = list() @@ -37,3 +47,55 @@ def cut_lines_between_angles(line_list, begin_angle, end_angle): cut_lines = cut_lines[::-1] return cut_lines + + +def plot_cut_line(line_list, begin_angle, end_angle, first_cut, cut_lines): + """Plot the original lines and the cut lines + Parameters + ---------- + line_list : [Line] + list of line to cut + begin_angle : float + Begin angle of the cut [rad] + end_angle : float + End angle of the cut [rad] + + """ + import matplotlib.pyplot as plt + + fig = plt.figure() + ax = fig.add_subplot(111) + + r = 0 + for line in line_list: + z1 = line.get_begin() + z2 = line.get_end() + ax.plot([z1.real, z2.real], [z1.imag, z2.imag], color='gray',label=f'split line') + r = max(r, abs(z1), abs(z2)) + + # plot cut lines + z1 = r * exp(1j * begin_angle) + z2 = r * exp(1j * end_angle) + + ax.plot([z1.real, -z1.real], [z1.imag, -z1.imag], color='r',label=f'cut') + ax.plot([z2.real, -z2.real], [z2.imag, -z2.imag], color='b',label=f'cut') + + for line in first_cut: + z1 = line.get_begin() + z2 = line.get_end() + ax.plot([z1.real, z2.real], [z1.imag, z2.imag], color='k',label=f'split line') + r = max(r, abs(z1), abs(z2)) + + for line in cut_lines: + z1 = line.get_begin() + z2 = line.get_end() + ax.plot([z1.real, z2.real], [z1.imag, z2.imag], color='k',label=f'split line', marker='.') + r = max(r, abs(z1), abs(z2)) + + + # plt.legend() + #axis to equal size + ax.axis('equal') + + plt.show() + From e6eea885b9d00c316f46670eeaa59a1d5e28dfb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=BCnther?= Date: Thu, 31 Jul 2025 15:53:39 +0200 Subject: [PATCH 6/9] [BC] geom. cutting: output steady line list --- .../Geometry/cut_lines_between_angle.py | 54 ++++++++++++------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/pyleecan/Functions/Geometry/cut_lines_between_angle.py b/pyleecan/Functions/Geometry/cut_lines_between_angle.py index 9f68dc259..9b912fe38 100644 --- a/pyleecan/Functions/Geometry/cut_lines_between_angle.py +++ b/pyleecan/Functions/Geometry/cut_lines_between_angle.py @@ -20,21 +20,34 @@ def cut_lines_between_angles(line_list, begin_angle, end_angle): cut_lines : [Line] Cut lines between the two angles """ - # normalize angles according to numpy.angle range + # normalize angles according to numpy.angle range, i.e. (-pi, pi] begin_angle = angle(exp(1j * begin_angle)) end_angle = angle(exp(1j * end_angle)) - mean_angle = angle(exp(1j * begin_angle) + exp(1j * end_angle)) # rotate list in case first/last line is in between begin and end angle # first copy list - sorted_list = [line for line in line_list] + rotated_list = [line for line in line_list] # rotate until first line is before begin angle - + rotate = True + ii = 0 + while rotate: + ang = angle(rotated_list[0].get_begin()) + if (begin_angle <= end_angle) and (ang < begin_angle or ang > end_angle): + rotate = False + elif ( + end_angle < ang < begin_angle + ): # begin and end angle cross -pi, pi boundary + rotate = False + if rotate: + rotated_list.append(rotated_list.pop(0)) + ii += 1 + if ii >= len(rotated_list): # rotation failed + rotate = False first_cut = list() cut_lines = list() # First cut - for line in line_list: + for line in rotated_list: top_split_list, _ = line.split_line(0, exp(1j * begin_angle)) first_cut.extend(top_split_list) # Second cut @@ -42,9 +55,17 @@ def cut_lines_between_angles(line_list, begin_angle, end_angle): _, bot_split_list = line.split_line(0, exp(1j * end_angle)) cut_lines.extend(bot_split_list) + # plot_cut_line(line_list, begin_angle, end_angle, first_cut, cut_lines) + # Check that lines are in the correct way - if (angle(cut_lines[0].get_begin()) % (2 * pi)) - (begin_angle % (2 * pi)) > 1e-6: - cut_lines = cut_lines[::-1] + if len(cut_lines) > 1: + EPS = 1e-6 + c1 = abs(angle(cut_lines[0].get_begin() * exp(-1j * end_angle))) + c2 = abs(angle(cut_lines[0].get_end() * exp(-1j * end_angle))) + c3 = abs(angle(cut_lines[-1].get_begin() * exp(-1j * begin_angle))) + c4 = abs(angle(cut_lines[-1].get_end() * exp(-1j * begin_angle))) + if (c1 < EPS or c2 < EPS) and (c3 < EPS or c4 < EPS): + cut_lines = cut_lines[::-1] return cut_lines @@ -70,32 +91,29 @@ def plot_cut_line(line_list, begin_angle, end_angle, first_cut, cut_lines): for line in line_list: z1 = line.get_begin() z2 = line.get_end() - ax.plot([z1.real, z2.real], [z1.imag, z2.imag], color='gray',label=f'split line') + ax.plot([z1.real, z2.real], [z1.imag, z2.imag], color="gray") r = max(r, abs(z1), abs(z2)) - + # plot cut lines z1 = r * exp(1j * begin_angle) z2 = r * exp(1j * end_angle) - ax.plot([z1.real, -z1.real], [z1.imag, -z1.imag], color='r',label=f'cut') - ax.plot([z2.real, -z2.real], [z2.imag, -z2.imag], color='b',label=f'cut') + ax.plot([z1.real, -z1.real], [z1.imag, -z1.imag], color="r") + ax.plot([z2.real, -z2.real], [z2.imag, -z2.imag], color="b") for line in first_cut: z1 = line.get_begin() z2 = line.get_end() - ax.plot([z1.real, z2.real], [z1.imag, z2.imag], color='k',label=f'split line') + ax.plot([z1.real, z2.real], [z1.imag, z2.imag], color="k") r = max(r, abs(z1), abs(z2)) for line in cut_lines: z1 = line.get_begin() z2 = line.get_end() - ax.plot([z1.real, z2.real], [z1.imag, z2.imag], color='k',label=f'split line', marker='.') + ax.plot([z1.real, z2.real], [z1.imag, z2.imag], color="k", marker=".") r = max(r, abs(z1), abs(z2)) - - # plt.legend() - #axis to equal size - ax.axis('equal') + # axis to equal size + ax.axis("equal") plt.show() - From e21998c271d4433f48bb391901ec7bb78ae545b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=BCnther?= Date: Fri, 1 Aug 2025 13:13:41 +0200 Subject: [PATCH 7/9] [CC] improved bore and notch merge --- Tests/Methods/Machine/test_bore_and_notch.py | 40 +-- .../Machine/Bore/merge_slot_intersect.py | 270 ++++++++---------- 2 files changed, 145 insertions(+), 165 deletions(-) diff --git a/Tests/Methods/Machine/test_bore_and_notch.py b/Tests/Methods/Machine/test_bore_and_notch.py index 2b655baeb..b43839ae2 100644 --- a/Tests/Methods/Machine/test_bore_and_notch.py +++ b/Tests/Methods/Machine/test_bore_and_notch.py @@ -13,6 +13,7 @@ mm = 1e-3 + @pytest.mark.IPMSM @pytest.mark.SCIM def test_bore_and_notch(is_show_fig=False): @@ -25,25 +26,29 @@ def test_bore_and_notch(is_show_fig=False): # Add notches to Toyota_Prius p = Toyota_Prius.get_pole_pair_number() - NBs = SlotCirc(Zs=24, W0=4 * mm, H0=1 * mm) - NBq = SlotCirc(Zs=2 * p, W0=4 * mm, H0=1 * mm) - NBdq = SlotCirc(Zs=2 * p, W0=6 * mm, H0=1 * mm) + Nq = SlotW26(Zs=2 * p, W0=1 * mm, H0=4 * mm, H1=0, R1=3 * mm, R2=3 * mm) NCirc1 = SlotCirc(Zs=2 * p, W0=8 * mm, H0=2 * mm) - NSlowW26 = SlotW26(Zs=2 * p, W0=1*mm, H0=2*mm, H1=0, R1=3*mm, R2=3*mm) - NSlowW26w = SlotW26(Zs=2 * p, W0=9*mm, H0=2*mm, H1=0, R1=5*mm, R2=5*mm) # wide slot - a0 = 0.25 + NCirc2 = SlotCirc(Zs=2 * p, W0=3 * mm, H0=1 * mm) + NSlotW26 = SlotW26(Zs=2 * p, W0=1 * mm, H0=2 * mm, H1=0, R1=3 * mm, R2=3 * mm) + + a0 = 0.2 + a1 = 0.33 Toyota_Prius.rotor.notch = [ - # NotchEvenDist(alpha=0, notch_shape=NBq), - # NotchEvenDist(alpha=0.5 * pi / p + a0, notch_shape=NBdq), - # NotchEvenDist(alpha=0.5 * pi / p - a0, notch_shape=NBdq), - # NotchEvenDist(alpha=0.5 * pi / p, notch_shape=NCirc1), - NotchEvenDist(alpha=0.5 * pi / p, notch_shape=NSlowW26w), + NotchEvenDist(alpha=0, notch_shape=Nq), # q-axis notch -> test sym. cut + NotchEvenDist(alpha=0.5 * pi / p + a0, notch_shape=NCirc1), # wide notch + NotchEvenDist(alpha=0.5 * pi / p - a0, notch_shape=NCirc1), # wide notch + NotchEvenDist( + alpha=0.5 * pi / p + a1, notch_shape=NCirc2 + ), # cut out completely + NotchEvenDist(alpha=0.5 * pi / p, notch_shape=NSlotW26), # small notch ] - delta_d = Toyota_Prius.stator.Rint - Toyota_Prius.rotor.Rext - Toyota_Prius.rotor.bore = BoreSinePole(N=8, delta_d=delta_d, delta_q=5*mm, W0=50*mm) + delta_d = Toyota_Prius.stator.Rint - Toyota_Prius.rotor.Rext + Toyota_Prius.rotor.bore = BoreSinePole( + N=8, delta_d=delta_d, delta_q=5 * mm, W0=50 * mm + ) - # Toyota_Prius.plot(sym=8, is_show_fig=is_show_fig) + Toyota_Prius.plot(sym=8, is_show_fig=is_show_fig) Toyota_Prius.plot(is_show_fig=is_show_fig) # Add notches to Audi_eTron @@ -52,14 +57,15 @@ def test_bore_and_notch(is_show_fig=False): Audi_eTron.stator.notch = [NotchEvenDist(alpha=0, notch_shape=NBs)] Audi_eTron.rotor.notch = [NotchEvenDist(alpha=0, notch_shape=NBr)] + Audi_eTron.stator.slot.H0 = 4 * mm + Audi_eTron.stator.bore = BoreFlower(N=4, Rarc=Audi_eTron.stator.Rint + 10 * mm) - # Audi_eTron.plot(sym=2, is_show_fig=is_show_fig) - # Audi_eTron.plot(is_show_fig=is_show_fig) + Audi_eTron.plot(sym=2, is_show_fig=is_show_fig) + Audi_eTron.plot(is_show_fig=is_show_fig) return Toyota_Prius, Audi_eTron if __name__ == "__main__": Toyota_Prius, Audi_eTron = test_bore_and_notch(is_show_fig=True) - plt.show() print("Done") diff --git a/pyleecan/Methods/Machine/Bore/merge_slot_intersect.py b/pyleecan/Methods/Machine/Bore/merge_slot_intersect.py index ff9417865..1f7ee1d48 100644 --- a/pyleecan/Methods/Machine/Bore/merge_slot_intersect.py +++ b/pyleecan/Methods/Machine/Bore/merge_slot_intersect.py @@ -3,6 +3,8 @@ from ....Functions.Geometry.cut_lines_between_angle import cut_lines_between_angles from ....Classes.Segment import Segment +DEBUG = False + def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): """Merge the Bore shape with notches/slot on the bore/yoke @@ -12,7 +14,7 @@ def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): Parameters ---------- radius_desc_list : list - List of dict to describe the bore/yoke radius + List of dict to describe the bore/yoke radius (without bore shape, with notches) prop_dict : dict Property dictionary to apply on the radius lines (not on slot/notch) sym : int @@ -23,171 +25,143 @@ def merge_slot_intersect(self, radius_desc_list, prop_dict, sym): line_list : list List of lines needed to draw the radius """ - # Get all Radius lines (0 to 2*pi) - radius_lines = self.get_bore_line() - - # fig, ax = None, None - # for desc in radius_desc_list: - # fig, ax = _plot_lines(desc['lines'], fig=fig, ax=ax, color="b") - # fig, ax = _plot_lines(radius_lines, fig=fig, ax=ax, color="gray") - # ax.axis('equal') - # fig.show() + # Get all Radius lines (0 to 2*pi), i.e. the bore shape without notches + bore_shape = self.get_bore_line() + if DEBUG: + _debug_plot(radius_desc_list, bore_shape, title="Original lines") - # Update begin and end angle if Radius (next step already cut lines) - if sym != 1 and radius_desc_list[0]["label"] == "Radius": - radius_desc_list[0]["begin_angle"] = 0 - if sym != 1 and radius_desc_list[-1]["label"] == "Radius": - radius_desc_list[-1]["end_angle"] = 2 * pi / sym + # limit begin and end angles + if sym != 1: + if radius_desc_list[0]["label"] == "Radius": + radius_desc_list[0]["begin_angle"] = 0 + if radius_desc_list[-1]["label"] == "Radius": + radius_desc_list[-1]["end_angle"] = 2 * pi / sym - # Replace Arc radius from desc by lines from shape + # search intersection of each notch with bore shape -> cut notch + for ii, desc_dict in enumerate(radius_desc_list): + if desc_dict["label"] != "Radius": + lines = [line for line in desc_dict["lines"]] + # forward search for 1. cut + found = False + while lines and not found: + for bore in bore_shape: + intersect = lines[0].intersect_obj(bore) + if intersect: + lines[0].split_point(intersect[0], is_begin=False) + found = True + break + if not found: + lines.pop(0) + + # backward search for 2nd cut + found = False + while lines and not found: + for bore in bore_shape: + intersect = lines[-1].intersect_obj(bore) + if intersect: + lines[-1].split_point(intersect[0], is_begin=True) + found = True + break + if not found: + lines.pop(-1) + + desc_dict["lines"] = lines + + if DEBUG: + _debug_plot(radius_desc_list, bore_shape, title="... after cutting notches") + + # fix radius_desc_list in case notches are cut out by bore shape completely + # TODO print warning + idx = [ii for ii, desc in enumerate(radius_desc_list) if not desc["lines"]] + + # correct previous and next segments begin and end angles first ... + siz = len(radius_desc_list) + for ii in idx: + if sym != 1 and ii == 0: + radius_desc_list[1]["begin_angle"] = 0 + elif sym != 1 and ii == (siz - 1): + radius_desc_list[-2]["end_angle"] = 2 * pi / sym + else: + previous_segment = radius_desc_list[ii - 1] + next_segment = radius_desc_list[(ii + 1) % siz] + # begin and end of cut out notch on round bore shape + begin = previous_segment["end_angle"] % (2 * pi) + end = next_segment["begin_angle"] % (2 * pi) + if begin <= end: + ang = (begin + end) / 2 + else: # zero crossing of angle + ang = ((begin + end + 2 * pi) / 2) % (2 * pi) + next_segment["begin_angle"] = ang + previous_segment["end_angle"] = ang + + # ... then remove cut out notches + for ii in idx[::-1]: + radius_desc_list.pop(ii) + + # replace round bore segments by actual bore shape + siz = len(radius_desc_list) for ii, desc_dict in enumerate(radius_desc_list): if desc_dict["label"] == "Radius": - desc_dict["lines"] = cut_lines_between_angles( - radius_lines, desc_dict["begin_angle"], desc_dict["end_angle"] - ) + previous_segment = radius_desc_list[ii - 1] + if previous_segment["label"] == "Radius": + begin = desc_dict["begin_angle"] + else: + begin = angle(previous_segment["lines"][-1].get_end()) + + next_segment = radius_desc_list[(ii + 1) % siz] + if next_segment["label"] == "Radius": + end = desc_dict["end_angle"] + else: + end = angle(next_segment["lines"][0].get_begin()) + + desc_dict["lines"] = cut_lines_between_angles(bore_shape, begin, end) + + if DEBUG: + _debug_plot(radius_desc_list, bore_shape, title="Merged (before sym. cutting)") - # If slot/notch are coliding with sym lines => Cut + # If notches are crossing sym lines => Cut if sym != 1: + begin = 0 + end = 2 * pi / sym # Cut first desc (if needed) if radius_desc_list[0]["begin_angle"] < 0: - lines = list() - for line in radius_desc_list[0]["lines"]: - top_split_list, _ = line.split_line(0, 1) - lines.extend(top_split_list) - radius_desc_list[0]["begin_angle"] = 0 + lines = cut_lines_between_angles(radius_desc_list[0]["lines"], begin, end) + radius_desc_list[0]["begin_angle"] = begin radius_desc_list[0]["lines"] = lines # Cut last desc (if needed) if radius_desc_list[-1]["end_angle"] > 2 * pi / sym: - lines = list() - for line in radius_desc_list[-1]["lines"]: - _, bot_split_list = line.split_line(0, exp(1j * 2 * pi / sym)) - lines.extend(bot_split_list) - radius_desc_list[-1]["end_angle"] = 2 * pi / sym + lines = cut_lines_between_angles(radius_desc_list[-1]["lines"], begin, end) + radius_desc_list[-1]["end_angle"] = end radius_desc_list[-1]["lines"] = lines - # Apply merge strategy on slot/notch - line_list = list() - for ii, desc_dict in enumerate(radius_desc_list): - if desc_dict["label"] == "Radius": - # Add prop_dict on all the Radius Lines - if prop_dict is not None: - for line in desc_dict["lines"]: - if line.prop_dict is None: - line.prop_dict = dict() - line.prop_dict.update(prop_dict) - line_list.extend(desc_dict["lines"]) - else: # Intersect and add slot/notch lines - # fig, ax = _plot_lines(desc_dict['lines'], is_show=True) - # Define First cutting line - # rad_line = radius_desc_list[ii - 1]["lines"][-1] - op = desc_dict["end_angle"] - desc_dict["begin_angle"] - if not (ii == 0 and sym != 1): # No first cut for first notch on Ox - rad_line_list = cut_lines_between_angles( - radius_lines, - desc_dict["begin_angle"] - op / 4, - desc_dict["begin_angle"] + op / 4, - ) - # Find first intersection between any line in rad_line_list - # and any line in desc_dict["lines"] - for cutting_line in rad_line_list[::-1]: - for jj, line in enumerate(desc_dict["lines"]): - inter_list = line.intersect_obj(cutting_line, is_on_line=True) - if inter_list: - break - if inter_list: - break - - # fig, ax = _plot_lines(desc_dict['lines'], is_show=False) - # fig, ax = _plot_lines([rad_line_list[-1]], color="r", fig=fig, ax=ax, is_show=True) - # fig, ax = _plot_lines([cutting_line], color="b", fig=fig, ax=ax, is_show=False) - # fig, ax = _plot_lines(line_list, color="g", linestyle="-.", fig=fig, ax=ax, is_show=True) - - if inter_list: - # slot/notch was cut => replace slot/notch lines by cut ones, i.e. - # keep all lines after the cut and update to start at cutting point - desc_dict["lines"] = desc_dict["lines"][jj:] - desc_dict["lines"][0].split_point(inter_list[0], is_begin=False) - if len(line_list) == 0: # Slot/notch on Ox - radius_desc_list[-1]["lines"][-1].split_point( - inter_list[0], is_begin=True - ) - else: - line_list[-1].split_point(inter_list[0], is_begin=True) - else: # the slot is above the bore shape => use bore shape lines - desc_dict["lines"] = cut_lines_between_angles( - radius_lines, desc_dict["begin_angle"], desc_dict["end_angle"] - ) - # Add prop_dict on all the Radius Lines - if prop_dict is not None: - for line in desc_dict["lines"]: - if line.prop_dict is None: - line.prop_dict = dict() - line.prop_dict.update(prop_dict) - line_list.extend(desc_dict["lines"]) - # fig, ax = _plot_lines(radius_lines) - # fig, ax = _plot_lines(desc_dict["lines"], fig=fig, ax=ax, color="b") - # fig, ax = _plot_lines([rad_line_list[-1]], fig=fig, ax=ax, color="r") - # fig, ax = _plot_point(rad_line_list[-1].get_begin(), fig=fig, ax=ax, color="r", marker=".") - # fig, ax = _plot_point(rad_line_list[-1].get_end(), fig=fig, ax=ax, color="r", marker=".", is_show=True) - continue # No need to cut the other side - - # Second cut - if not (ii == len(radius_desc_list) - 1 and sym != 1): - # No second cut for notch on sym line - rad_line_list = cut_lines_between_angles( - radius_lines, - desc_dict["end_angle"] - op / 4, - desc_dict["end_angle"] + op / 4, - ) - - for cutting_line in rad_line_list: - for jj, line in enumerate(desc_dict["lines"][::-1]): - inter_list = line.intersect_obj(cutting_line, is_on_line=True) - if inter_list: - break - if inter_list: - break + if DEBUG: + _debug_plot(radius_desc_list, bore_shape, title="Merged completely") - if inter_list: - # Slot/notch was cut => Replace lines by cut ones - if jj != 0: # Keep all the lines if last line is cut - # keep all lines before cut - desc_dict["lines"] = desc_dict["lines"][:-jj] - # update lines to end at cutting point - desc_dict["lines"][-1].split_point(inter_list[0], is_begin=True) - radius_desc_list[ii + 1]["lines"][0].split_point( - inter_list[0], is_begin=False - ) - # Add slot/notch lines to final list - line_list.extend(desc_dict["lines"]) - return line_list + line_list = [line for desc_list in radius_desc_list for line in desc_list["lines"]] + # Apply properties + if prop_dict is not None: + for line in line_list: + if line.prop_dict is None: + line.prop_dict = dict() + line.prop_dict.update(prop_dict) -def _plot_lines( - lines, color="k", linestyle="-", linewidth=1, fig=None, ax=None, is_show=False - ): - - # fig, ax = None, None - for line in lines: - fig, ax = line.plot( - fig=fig, ax=ax, color=color, linewidth=linewidth, linestyle=linestyle - ) - - if is_show: - ax.axis('equal') - fig.show() + return line_list - return fig, ax -def _plot_point( - point, color="k", marker="o", markersize=10, fig=None, ax=None, is_show=False - ): - - ax.plot(point.real, point.imag, marker=marker, markersize=markersize, color=color) +def _debug_plot(radius_desc_list, bore_shape=list(), title=""): + """Helper function for debugging""" + kwargs = dict(color="b", linewidth="1", linestyle="-") + fig, ax = None, None + for desc in radius_desc_list: + for line in desc["lines"]: + fig, ax = line.plot(fig=fig, ax=ax, **kwargs) - if is_show: - ax.axis('equal') - fig.show() + kwargs = dict(color="gray", linewidth="1", linestyle="-.") + for line in bore_shape: + fig, ax = line.plot(fig=fig, ax=ax, **kwargs) - return fig, ax + ax.axis("equal") + ax.set(title=title) + fig.show() From ceb52d26e71120a2ef1f7741c7b9cdb57ffb6682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=BCnther?= Date: Fri, 1 Aug 2025 14:12:40 +0200 Subject: [PATCH 8/9] [BC] minor fix for notch and bore merge --- Tests/Methods/Machine/test_bore_and_notch.py | 38 ++++++++++++++++++- .../Machine/Bore/merge_slot_connect.py | 37 +++++++----------- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/Tests/Methods/Machine/test_bore_and_notch.py b/Tests/Methods/Machine/test_bore_and_notch.py index b43839ae2..c4d6efda2 100644 --- a/Tests/Methods/Machine/test_bore_and_notch.py +++ b/Tests/Methods/Machine/test_bore_and_notch.py @@ -16,7 +16,40 @@ @pytest.mark.IPMSM @pytest.mark.SCIM -def test_bore_and_notch(is_show_fig=False): +def test_bore_and_notch_merge_type_0(is_show_fig=False): + """Validation of bore shape and notches""" + + # Load machines + Toyota_Prius = load(join(DATA_DIR, "Machine", "Toyota_Prius.json")) + + # Add notches to Toyota_Prius + p = Toyota_Prius.get_pole_pair_number() + + Nq = SlotCirc(Zs=2 * p, W0=5 * mm, H0=2 * mm) + NCirc1 = SlotCirc(Zs=2 * p, W0=8 * mm, H0=2 * mm) + + a0 = 0.2 + + Toyota_Prius.rotor.notch = [ + NotchEvenDist(alpha=0, notch_shape=Nq), # q-axis notch -> test sym. cut + NotchEvenDist(alpha=0.5 * pi / p + a0, notch_shape=NCirc1), # wide notch + NotchEvenDist(alpha=0.5 * pi / p - a0, notch_shape=NCirc1), # wide notch + ] + delta_d = Toyota_Prius.stator.Rint - Toyota_Prius.rotor.Rext + Toyota_Prius.rotor.bore = BoreSinePole( + N=8, delta_d=delta_d, delta_q=3 * mm, W0=50 * mm + ) + Toyota_Prius.rotor.bore.type_merge_slot = 0 + + Toyota_Prius.plot(sym=8, is_show_fig=is_show_fig) + Toyota_Prius.plot(is_show_fig=is_show_fig) + + return Toyota_Prius + + +@pytest.mark.IPMSM +@pytest.mark.SCIM +def test_bore_and_notch_merge_type_1(is_show_fig=False): """Validation of rotor and stator notches""" # Load machines @@ -67,5 +100,6 @@ def test_bore_and_notch(is_show_fig=False): if __name__ == "__main__": - Toyota_Prius, Audi_eTron = test_bore_and_notch(is_show_fig=True) + Toyota_Prius = test_bore_and_notch_merge_type_0(is_show_fig=True) + # Toyota_Prius, Audi_eTron = test_bore_and_notch_merge_type_1(is_show_fig=True) print("Done") diff --git a/pyleecan/Methods/Machine/Bore/merge_slot_connect.py b/pyleecan/Methods/Machine/Bore/merge_slot_connect.py index 61e48c41e..df1d1862b 100644 --- a/pyleecan/Methods/Machine/Bore/merge_slot_connect.py +++ b/pyleecan/Methods/Machine/Bore/merge_slot_connect.py @@ -7,7 +7,7 @@ def merge_slot_connect(self, radius_desc_list, prop_dict, sym): """Merge the Bore shape with notches/slot on the bore/yoke Connect method: Add lines between radius and notch/slot - (To use when the radius shape have circular part matchine the radius + (To use when the radius shape have circular part matching the radius or when radius lines are bellow normal radius) Parameters @@ -61,6 +61,7 @@ def merge_slot_connect(self, radius_desc_list, prop_dict, sym): radius_desc_list[-1]["lines"] = lines # Apply merge strategy on slot/notch + siz = len(radius_desc_list) line_list = list() for ii, desc_dict in enumerate(radius_desc_list): if desc_dict["label"] == "Radius": @@ -72,30 +73,18 @@ def merge_slot_connect(self, radius_desc_list, prop_dict, sym): line.prop_dict.update(prop_dict) line_list.extend(desc_dict["lines"]) else: # Connect and add notch lines + lines = desc_dict["lines"] if len(line_list) > 0: # Connect Radius to slot/notch by Segment (if needed) - if ( - abs(line_list[-1].get_end() - desc_dict["lines"][0].get_begin()) - > 1e-6 - ): - line_list.append( - Segment( - line_list[-1].get_end(), desc_dict["lines"][0].get_begin() - ) - ) - line_list.extend(desc_dict["lines"]) + if abs(line_list[-1].get_end() - lines[0].get_begin()) > 1e-6: + connection = Segment(line_list[-1].get_end(), lines[0].get_begin()) + line_list.append(connection) + line_list.extend(lines) + # Connect slot/notch to next radius - if ( - abs( - radius_desc_list[ii + 1]["lines"][0].get_begin() - - desc_dict["lines"][-1].get_end() - ) - > 1e-6 - ): - line_list.append( - Segment( - desc_dict["lines"][-1].get_end(), - radius_desc_list[ii + 1]["lines"][0].get_begin(), - ) - ) + next_lines = radius_desc_list[(ii + 1) % siz]["lines"] + if abs(next_lines[0].get_begin() - lines[-1].get_end()) > 1e-6: + connection = Segment(lines[-1].get_end(), next_lines[0].get_begin()) + if not (sym != 1 and ii == (siz - 1)): + line_list.append(connection) return line_list From 844aed3ddd2bca94c5a847866874e8de05881ab0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20G=C3=BCnther?= Date: Tue, 5 Aug 2025 10:41:33 +0200 Subject: [PATCH 9/9] [NF] opt. translate notch/slot on bore shape --- Tests/Methods/Machine/test_bore_and_notch.py | 42 +++++++++- .../Methods/Geometry/Segment/is_on_line.py | 5 +- .../Machine/Bore/merge_slot_translate.py | 81 ++++++++++++++++++- 3 files changed, 123 insertions(+), 5 deletions(-) diff --git a/Tests/Methods/Machine/test_bore_and_notch.py b/Tests/Methods/Machine/test_bore_and_notch.py index c4d6efda2..3ddcfe58c 100644 --- a/Tests/Methods/Machine/test_bore_and_notch.py +++ b/Tests/Methods/Machine/test_bore_and_notch.py @@ -99,7 +99,47 @@ def test_bore_and_notch_merge_type_1(is_show_fig=False): return Toyota_Prius, Audi_eTron +@pytest.mark.IPMSM +@pytest.mark.SCIM +def test_bore_and_notch_merge_type_2(is_show_fig=False): + """Validation of rotor and stator notches""" + + # Load machines + Toyota_Prius = load(join(DATA_DIR, "Machine", "Toyota_Prius.json")) + + # Add notches to Toyota_Prius + p = Toyota_Prius.get_pole_pair_number() + + Nq = SlotW26(Zs=2 * p, W0=1 * mm, H0=4 * mm, H1=0, R1=3 * mm, R2=3 * mm) + NCirc1 = SlotCirc(Zs=2 * p, W0=8 * mm, H0=2 * mm) + NCirc2 = SlotCirc(Zs=2 * p, W0=3 * mm, H0=1 * mm) + NSlotW26 = SlotW26(Zs=2 * p, W0=1 * mm, H0=2 * mm, H1=0, R1=3 * mm, R2=3 * mm) + + a0 = 0.2 + a1 = 0.33 + + Toyota_Prius.rotor.notch = [ + NotchEvenDist(alpha=0, notch_shape=Nq), # q-axis notch -> test sym. cut + NotchEvenDist(alpha=0.5 * pi / p + a0, notch_shape=NCirc1), # wide notch + NotchEvenDist(alpha=0.5 * pi / p - a0, notch_shape=NCirc1), # wide notch + NotchEvenDist(alpha=0.5 * pi / p + a1, notch_shape=NCirc2), # cut out at all + NotchEvenDist(alpha=0.5 * pi / p, notch_shape=NSlotW26), # small notch + ] + delta_d = Toyota_Prius.stator.Rint - Toyota_Prius.rotor.Rext + Toyota_Prius.rotor.bore = BoreSinePole( + N=8, delta_d=delta_d, delta_q=5 * mm, W0=50 * mm + ) + + Toyota_Prius.rotor.bore.type_merge_slot = 2 + + Toyota_Prius.plot(sym=8, is_show_fig=is_show_fig) + Toyota_Prius.plot(is_show_fig=is_show_fig) + + return Toyota_Prius + + if __name__ == "__main__": - Toyota_Prius = test_bore_and_notch_merge_type_0(is_show_fig=True) + # Toyota_Prius = test_bore_and_notch_merge_type_0(is_show_fig=True) # Toyota_Prius, Audi_eTron = test_bore_and_notch_merge_type_1(is_show_fig=True) + Toyota_Prius = test_bore_and_notch_merge_type_2(is_show_fig=True) print("Done") diff --git a/pyleecan/Methods/Geometry/Segment/is_on_line.py b/pyleecan/Methods/Geometry/Segment/is_on_line.py index 925f0853c..34ba99586 100644 --- a/pyleecan/Methods/Geometry/Segment/is_on_line.py +++ b/pyleecan/Methods/Geometry/Segment/is_on_line.py @@ -2,7 +2,7 @@ def is_on_line(self, Z): - """Check is a point defined by its complex coordinate is on the segment + """Check if a point defined by its complex coordinate is on the segment Parameters ---------- @@ -26,6 +26,7 @@ def is_on_line(self, Z): if abs(Z12.real * Z13.imag - Z12.imag * Z13.real) < 1e-10: K13 = Z12.real * Z13.real + Z12.imag * Z13.imag K12 = Z12.real * Z12.real + Z12.imag * Z12.imag - if K13 >= 0 and K13 <= K12: + eps = 1e-12 + if K13 >= -eps and K13 <= K12 + eps: return True return False diff --git a/pyleecan/Methods/Machine/Bore/merge_slot_translate.py b/pyleecan/Methods/Machine/Bore/merge_slot_translate.py index 27ac97fe3..8d203070d 100644 --- a/pyleecan/Methods/Machine/Bore/merge_slot_translate.py +++ b/pyleecan/Methods/Machine/Bore/merge_slot_translate.py @@ -1,3 +1,11 @@ +from numpy import pi, exp, angle + +from ....Functions.Geometry.cut_lines_between_angle import cut_lines_between_angles +from ....Classes.Segment import Segment + +DEBUG = False + + def merge_slot_translate(self, radius_desc_list, prop_dict, sym): """Merge the Bore shape with notches/slot on the bore/yoke Translate method: Translate lines of notch/slot to match the radius of the shape @@ -6,7 +14,7 @@ def merge_slot_translate(self, radius_desc_list, prop_dict, sym): Parameters ---------- radius_desc_list : list - List of dict to describe the bore/yoke radius + List of dict to describe the bore/yoke radius (without bore shape, with notches) prop_dict : dict Property dictionary to apply on the radius lines (not on slot/notch) sym : int @@ -17,5 +25,74 @@ def merge_slot_translate(self, radius_desc_list, prop_dict, sym): line_list : list List of lines needed to draw the radius """ + # Get all Radius lines (0 to 2*pi), i.e. the bore shape without notches + bore_shape = self.get_bore_line() + + Rbo = self.parent.get_Rbo() + + if DEBUG: + _debug_plot(radius_desc_list, bore_shape, title="Original lines") + + # limit begin and end angles + if sym != 1: + if radius_desc_list[0]["label"] == "Radius": + radius_desc_list[0]["begin_angle"] = 0 + if radius_desc_list[-1]["label"] == "Radius": + radius_desc_list[-1]["end_angle"] = 2 * pi / sym + + # search intersection of bore shape with mean opening angle of slots/notches ... + # ... and translate notch to bore shape + for ii, desc_dict in enumerate(radius_desc_list): + if desc_dict["label"] != "Radius": + lines = desc_dict["lines"] + begin = desc_dict["begin_angle"] % (2 * pi) + end = desc_dict["end_angle"] % (2 * pi) + op = (begin + end) / 2 + if begin > end: + op = ((begin + end + 2 * pi) / 2) % (2 * pi) + R = 1 / 2 * abs(lines[0].get_begin() + lines[-1].get_end()) + Z = R * exp(1j * op) + line = Segment(0, 2 * Rbo * exp(1j * op)) # be sure to cross bore shape + found = False + for bore in bore_shape: + intersect = line.intersect_obj(bore) + if intersect: + found = True + break + if found: + dZ = intersect[0] - Z + for line in lines: + line.translate(dZ) + + # close gap between notch lines and round bore shape for next step + line = Segment(lines[0].get_begin() - dZ, lines[0].get_begin()) + lines.insert(0, line) + + line = Segment(lines[-1].get_end(), lines[-1].get_end() - dZ) + lines.append(line) + else: + self.get_logger().warning("Warning: Can't translate notch/slot.") + + if DEBUG: + _debug_plot(radius_desc_list, bore_shape, title="translated lines (w/o gaps)") + + line_list = self.merge_slot_intersect(radius_desc_list, prop_dict, sym) + + return line_list + + +def _debug_plot(radius_desc_list, bore_shape=list(), title=""): + """Helper function for debugging""" + kwargs = dict(color="b", linewidth="1", linestyle="-") + fig, ax = None, None + for desc in radius_desc_list: + for line in desc["lines"]: + fig, ax = line.plot(fig=fig, ax=ax, **kwargs) + + kwargs = dict(color="gray", linewidth="1", linestyle="-.") + for line in bore_shape: + fig, ax = line.plot(fig=fig, ax=ax, **kwargs) - raise Exception("Not Implemented Yet") + ax.axis("equal") + ax.set(title=title) + fig.show()