{ "cells": [ { "cell_type": "markdown", "id": "9b68c628", "metadata": {}, "source": [ "# PM synchronous motor transient analysis\n", "\n", "This example shows how to use PyAEDT to create a Maxwell 2D transient analysis for\n", "an interior permanent magnet (PM) electric motor.\n", "\n", "Keywords: **Maxwell 2D**, **transient**, **motor**." ] }, { "cell_type": "markdown", "id": "d00a23fa", "metadata": {}, "source": [ "## Perform imports and define constants\n", "\n", "Perform required imports." ] }, { "cell_type": "code", "execution_count": null, "id": "e8c5eea6", "metadata": {}, "outputs": [], "source": [ "import csv\n", "import os\n", "import tempfile\n", "import time\n", "from operator import attrgetter" ] }, { "cell_type": "code", "execution_count": null, "id": "25317ddf", "metadata": {}, "outputs": [], "source": [ "import ansys.aedt.core" ] }, { "cell_type": "markdown", "id": "de541291", "metadata": {}, "source": [ "Define constants." ] }, { "cell_type": "code", "execution_count": null, "id": "cf0b098a", "metadata": {}, "outputs": [], "source": [ "AEDT_VERSION = \"2024.2\"\n", "NUM_CORES = 4\n", "NG_MODE = False # Open AEDT UI when it is launched." ] }, { "cell_type": "markdown", "id": "eb5c5df1", "metadata": {}, "source": [ "## Create temporary directory and download files\n", "\n", "Create a temporary directory where downloaded data or\n", "dumped data can be stored.\n", "If you'd like to retrieve the project data for subsequent use,\n", "the temporary folder name is given by ``temp_folder.name``." ] }, { "cell_type": "code", "execution_count": null, "id": "1ea2ec58", "metadata": {}, "outputs": [], "source": [ "temp_folder = tempfile.TemporaryDirectory(suffix=\".ansys\")" ] }, { "cell_type": "markdown", "id": "6790bbcb", "metadata": {}, "source": [ "## Initialize dictionaries\n", "\n", "Dictionaries contain all the definitions for the design variables and output variables." ] }, { "cell_type": "markdown", "id": "a2855cec", "metadata": {}, "source": [ "## Initialize definitions for th stator, rotor, and shaft\n", "\n", "Initialize geometry parameter definitions for the stator, rotor, and shaft.\n", "The naming refers to RMxprt primitives." ] }, { "cell_type": "code", "execution_count": null, "id": "b7ca6a74", "metadata": {}, "outputs": [], "source": [ "geom_params = {\n", " \"DiaGap\": \"132mm\",\n", " \"DiaStatorYoke\": \"198mm\",\n", " \"DiaStatorInner\": \"132mm\",\n", " \"DiaRotorLam\": \"130mm\",\n", " \"DiaShaft\": \"44.45mm\",\n", " \"DiaOuter\": \"198mm\",\n", " \"Airgap\": \"1mm\",\n", " \"SlotNumber\": \"48\",\n", " \"SlotType\": \"3\",\n", "}" ] }, { "cell_type": "markdown", "id": "8e6619d1", "metadata": {}, "source": [ "## Initialize definitions for stator windings\n", "\n", "Initialize geometry parameter definitions for the stator windings. The naming\n", "refers to RMxprt primitives." ] }, { "cell_type": "code", "execution_count": null, "id": "8068cd7a", "metadata": {}, "outputs": [], "source": [ "wind_params = {\n", " \"Layers\": \"1\",\n", " \"ParallelPaths\": \"2\",\n", " \"R_Phase\": \"7.5mOhm\",\n", " \"WdgExt_F\": \"5mm\",\n", " \"SpanExt\": \"30mm\",\n", " \"SegAngle\": \"0.25\",\n", " \"CoilPitch\": \"5\", # coil pitch in slots\n", " \"Coil_SetBack\": \"3.605732823mm\",\n", " \"SlotWidth\": \"2.814mm\", # RMxprt Bs0\n", " \"Coil_Edge_Short\": \"3.769235435mm\",\n", " \"Coil_Edge_Long\": \"15.37828521mm\",\n", "}" ] }, { "cell_type": "markdown", "id": "62f8d5fe", "metadata": {}, "source": [ "## Initialize definitions for model setup\n", "\n", "Initialize geometry parameter definitions for the model setup." ] }, { "cell_type": "code", "execution_count": null, "id": "6de66970", "metadata": {}, "outputs": [], "source": [ "mod_params = {\n", " \"NumPoles\": \"8\",\n", " \"Model_Length\": \"80mm\",\n", " \"SymmetryFactor\": \"8\",\n", " \"Magnetic_Axial_Length\": \"150mm\",\n", " \"Stator_Lam_Length\": \"0mm\",\n", " \"StatorSkewAngle\": \"0deg\",\n", " \"NumTorquePointsPerCycle\": \"30\",\n", " \"mapping_angle\": \"0.125*4deg\",\n", " \"num_m\": \"16\",\n", " \"Section_Angle\": \"360deg/SymmetryFactor\",\n", "}" ] }, { "cell_type": "markdown", "id": "c2c447c0", "metadata": {}, "source": [ "## Initialize definitions for operational machine\n", "\n", "Initialize geometry parameter definitions for the operational machine. This\n", "identifies the operating point for the transient setup." ] }, { "cell_type": "code", "execution_count": null, "id": "93c630c1", "metadata": {}, "outputs": [], "source": [ "oper_params = {\n", " \"InitialPositionMD\": \"180deg/4\",\n", " \"IPeak\": \"480A\",\n", " \"MachineRPM\": \"3000rpm\",\n", " \"ElectricFrequency\": \"MachineRPM/60rpm*NumPoles/2*1Hz\",\n", " \"ElectricPeriod\": \"1/ElectricFrequency\",\n", " \"BandTicksinModel\": \"360deg/NumPoles/mapping_angle\",\n", " \"TimeStep\": \"ElectricPeriod/(2*BandTicksinModel)\",\n", " \"StopTime\": \"ElectricPeriod\",\n", " \"Theta_i\": \"135deg\",\n", "}" ] }, { "cell_type": "markdown", "id": "5bafa344", "metadata": {}, "source": [ "## Launch AEDT and Maxwell 2D\n", "\n", "Launch AEDT and Maxwell 2D after first setting up the project and design names,\n", "the solver, and the version. The following code also creates an instance of the\n", "``Maxwell2d`` class named ``m2d``." ] }, { "cell_type": "code", "execution_count": null, "id": "7a4fda45", "metadata": {}, "outputs": [], "source": [ "project_name = os.path.join(temp_folder.name, \"PM_Motor.aedt\")\n", "m2d = ansys.aedt.core.Maxwell2d(\n", " project=project_name,\n", " version=AEDT_VERSION,\n", " design=\"Sinusoidal\",\n", " solution_type=\"TransientXY\",\n", " new_desktop=True,\n", " non_graphical=NG_MODE,\n", ")" ] }, { "cell_type": "markdown", "id": "418b2176", "metadata": {}, "source": [ "## Define modeler units" ] }, { "cell_type": "code", "execution_count": null, "id": "6415ba82", "metadata": {}, "outputs": [], "source": [ "m2d.modeler.model_units = \"mm\"" ] }, { "cell_type": "markdown", "id": "9a2f377b", "metadata": {}, "source": [ "## Define variables from dictionaries\n", "\n", "Define design variables from the created dictionaries." ] }, { "cell_type": "code", "execution_count": null, "id": "09491a96", "metadata": {}, "outputs": [], "source": [ "for k, v in geom_params.items():\n", " m2d[k] = v\n", "for k, v in wind_params.items():\n", " m2d[k] = v\n", "for k, v in mod_params.items():\n", " m2d[k] = v\n", "for k, v in oper_params.items():\n", " m2d[k] = v" ] }, { "cell_type": "markdown", "id": "99d7281f", "metadata": {}, "source": [ "## Define path for non-linear material properties\n", "\n", "Define the path for non-linear material properties.\n", "Materials are stored in text files." ] }, { "cell_type": "code", "execution_count": null, "id": "bc1257c5", "metadata": {}, "outputs": [], "source": [ "filename_lam, filename_PM = ansys.aedt.core.downloads.download_leaf(\n", " destination=temp_folder.name\n", ")" ] }, { "cell_type": "markdown", "id": "bcf0768a", "metadata": {}, "source": [ "## Create first material\n", "\n", "Create the material ``\"Copper (Annealed)_65C\"``." ] }, { "cell_type": "code", "execution_count": null, "id": "3278f589", "metadata": {}, "outputs": [], "source": [ "mat_coils = m2d.materials.add_material(\"Copper (Annealed)_65C\")\n", "mat_coils.update()\n", "mat_coils.conductivity = \"49288048.9198\"\n", "mat_coils.permeability = \"1\"" ] }, { "cell_type": "markdown", "id": "a88e26b9", "metadata": {}, "source": [ "## Create second material\n", "\n", "Create the material ``\"Arnold_Magnetics_N30UH_80C\"``.\n", "The BH curve is read from a tabbed CSV file. A list named ``BH_List_PM``\n", "is created. This list is passed to the ``mat_PM.permeability.value``\n", "variable." ] }, { "cell_type": "code", "execution_count": null, "id": "234b2680", "metadata": {}, "outputs": [], "source": [ "mat_PM = m2d.materials.add_material(name=\"Arnold_Magnetics_N30UH_80C_new\")\n", "mat_PM.update()\n", "mat_PM.conductivity = \"555555.5556\"\n", "mat_PM.set_magnetic_coercivity(value=-800146.66287534, x=1, y=0, z=0)\n", "mat_PM.mass_density = \"7500\"\n", "BH_List_PM = []\n", "with open(filename_PM) as f:\n", " reader = csv.reader(f, delimiter=\"\\t\")\n", " next(reader)\n", " for row in reader:\n", " BH_List_PM.append([float(row[0]), float(row[1])])\n", "mat_PM.permeability.value = BH_List_PM" ] }, { "cell_type": "markdown", "id": "16ed6223", "metadata": {}, "source": [ "## Create third material\n", "\n", "Create the laminated material ``30DH_20C_smooth``.\n", "This material has a BH curve and a core loss model,\n", "which is set to electrical steel." ] }, { "cell_type": "code", "execution_count": null, "id": "081f99a6", "metadata": {}, "outputs": [], "source": [ "mat_lam = m2d.materials.add_material(\"30DH_20C_smooth\")\n", "mat_lam.update()\n", "mat_lam.conductivity = \"1694915.25424\"\n", "kh = 71.7180985413\n", "kc = 0.25092214579\n", "ke = 12.1625774023\n", "kdc = 0.001\n", "eq_depth = 0.001\n", "mat_lam.set_electrical_steel_coreloss(kh, kc, ke, kdc, eq_depth)\n", "mat_lam.mass_density = \"7650\"\n", "BH_List_lam = []\n", "with open(filename_lam) as f:\n", " reader = csv.reader(f, delimiter=\"\\t\")\n", " next(reader)\n", " for row in reader:\n", " BH_List_lam.append([float(row[0]), float(row[1])])\n", "mat_lam.permeability.value = BH_List_lam" ] }, { "cell_type": "markdown", "id": "db372e75", "metadata": {}, "source": [ "## Create geometry for stator\n", "\n", "Create the geometry for the stator. It is created via\n", "the RMxprt user-defined primitive (UDP). A list of lists is\n", "created with the proper UDP parameters." ] }, { "cell_type": "code", "execution_count": null, "id": "293fe6b2", "metadata": {}, "outputs": [], "source": [ "udp_par_list_stator = [\n", " [\"DiaGap\", \"DiaGap\"],\n", " [\"DiaYoke\", \"DiaStatorYoke\"],\n", " [\"Length\", \"Stator_Lam_Length\"],\n", " [\"Skew\", \"StatorSkewAngle\"],\n", " [\"Slots\", \"SlotNumber\"],\n", " [\"SlotType\", \"SlotType\"],\n", " [\"Hs0\", \"1.2mm\"],\n", " [\"Hs01\", \"0mm\"],\n", " [\"Hs1\", \"0.4834227384999mm\"],\n", " [\"Hs2\", \"17.287669825502mm\"],\n", " [\"Bs0\", \"2.814mm\"],\n", " [\"Bs1\", \"4.71154109036mm\"],\n", " [\"Bs2\", \"6.9777285790998mm\"],\n", " [\"Rs\", \"2mm\"],\n", " [\"FilletType\", \"1\"],\n", " [\"HalfSlot\", \"0\"],\n", " [\"VentHoles\", \"0\"],\n", " [\"HoleDiaIn\", \"0mm\"],\n", " [\"HoleDiaOut\", \"0mm\"],\n", " [\"HoleLocIn\", \"0mm\"],\n", " [\"HoleLocOut\", \"0mm\"],\n", " [\"VentDucts\", \"0\"],\n", " [\"DuctWidth\", \"0mm\"],\n", " [\"DuctPitch\", \"0mm\"],\n", " [\"SegAngle\", \"0deg\"],\n", " [\"LenRegion\", \"Model_Length\"],\n", " [\"InfoCore\", \"0\"],\n", "]\n", "\n", "stator_id = m2d.modeler.create_udp(\n", " dll=\"RMxprt/VentSlotCore.dll\",\n", " parameters=udp_par_list_stator,\n", " library=\"syslib\",\n", " name=\"my_stator\",\n", ")\n" ] }, { "cell_type": "markdown", "id": "0937a6c7", "metadata": {}, "source": [ "## Assign properties to stator\n", "\n", "Assign properties to the stator. The following code assigns\n", "the ``material``, ``name``, ``color``, and ``solve_inside`` properties." ] }, { "cell_type": "code", "execution_count": null, "id": "1a79d553", "metadata": {}, "outputs": [], "source": [ "m2d.assign_material(assignment=stator_id, material=\"30DH_20C_smooth\")\n", "stator_id.name = \"Stator\"\n", "stator_id.color = (0, 0, 255) # rgb" ] }, { "cell_type": "code", "execution_count": null, "id": "6881673e", "metadata": {}, "outputs": [], "source": [ "# to be reassigned: m2d.assign material puts False if not dielectric\n", "stator_id.solve_inside = True" ] }, { "cell_type": "markdown", "id": "490a53ad", "metadata": {}, "source": [ "## Create outer and inner PMs\n", "\n", "Create the outer and inner PMs and assign color to them." ] }, { "cell_type": "code", "execution_count": null, "id": "4b76357c", "metadata": {}, "outputs": [], "source": [ "IM1_points = [\n", " [56.70957112, 3.104886585, 0],\n", " [40.25081875, 16.67243502, 0],\n", " [38.59701538, 14.66621111, 0],\n", " [55.05576774, 1.098662669, 0],\n", "]\n", "OM1_points = [\n", " [54.37758185, 22.52393189, 0],\n", " [59.69688156, 9.68200639, 0],\n", " [63.26490432, 11.15992981, 0],\n", " [57.94560461, 24.00185531, 0],\n", "]\n", "IPM1_id = m2d.modeler.create_polyline(\n", " points=IM1_points,\n", " cover_surface=True,\n", " name=\"PM_I1\",\n", " material=\"Arnold_Magnetics_N30UH_80C_new\",\n", ")\n", "IPM1_id.color = (0, 128, 64)\n", "OPM1_id = m2d.modeler.create_polyline(\n", " points=OM1_points,\n", " cover_surface=True,\n", " name=\"PM_O1\",\n", " material=\"Arnold_Magnetics_N30UH_80C_new\",\n", ")\n", "OPM1_id.color = (0, 128, 64)" ] }, { "cell_type": "markdown", "id": "a792f1c6", "metadata": {}, "source": [ "## Create coordinate system for PMs\n", "\n", "Create the coordinate system for the PMs.\n", "In Maxwell 2D, you assign magnetization via the coordinate system.\n", "The inputs are the object name, coordinate system name, and inner or outer magnetization." ] }, { "cell_type": "code", "execution_count": null, "id": "1fcfb311", "metadata": {}, "outputs": [], "source": [ "def create_cs_magnets(pm_id, cs_name, point_direction):\n", " edges = sorted(pm_id.edges, key=attrgetter(\"length\"), reverse=True)\n", "\n", " if point_direction == \"outer\":\n", " my_axis_pos = edges[0]\n", " elif point_direction == \"inner\":\n", " my_axis_pos = edges[1]\n", "\n", " m2d.modeler.create_face_coordinate_system(\n", " face=pm_id.faces[0],\n", " origin=pm_id.faces[0],\n", " axis_position=my_axis_pos,\n", " axis=\"X\",\n", " name=cs_name,\n", " )\n", " pm_id.part_coordinate_system = cs_name\n", " m2d.modeler.set_working_coordinate_system(\"Global\")" ] }, { "cell_type": "markdown", "id": "76bd559e", "metadata": {}, "source": [ "## Create coordinate system for PMs in face center\n", "\n", "Create the coordinate system for PMs in the face center." ] }, { "cell_type": "code", "execution_count": null, "id": "af050d04", "metadata": {}, "outputs": [], "source": [ "create_cs_magnets(IPM1_id, \"CS_\" + IPM1_id.name, \"outer\")\n", "create_cs_magnets(OPM1_id, \"CS_\" + OPM1_id.name, \"outer\")" ] }, { "cell_type": "markdown", "id": "e00678df", "metadata": {}, "source": [ "## Duplicate and mirror PMs\n", "\n", "Duplicate and mirror the PMs along with the local coordinate system." ] }, { "cell_type": "code", "execution_count": null, "id": "63e562e1", "metadata": {}, "outputs": [], "source": [ "m2d.modeler.duplicate_and_mirror(\n", " assignment=[IPM1_id, OPM1_id],\n", " origin=[0, 0, 0],\n", " vector=[\n", " \"cos((360deg/SymmetryFactor/2)+90deg)\",\n", " \"sin((360deg/SymmetryFactor/2)+90deg)\",\n", " 0,\n", " ],\n", ")\n", "id_PMs = m2d.modeler.get_objects_w_string(string_name=\"PM\", case_sensitive=True)" ] }, { "cell_type": "markdown", "id": "0291ec6e", "metadata": {}, "source": [ "## Create coils" ] }, { "cell_type": "code", "execution_count": null, "id": "4958c5d9", "metadata": {}, "outputs": [], "source": [ "coil_id = m2d.modeler.create_rectangle(\n", " origin=[\"DiaRotorLam/2+Airgap+Coil_SetBack\", \"-Coil_Edge_Short/2\", 0],\n", " sizes=[\"Coil_Edge_Long\", \"Coil_Edge_Short\", 0],\n", " name=\"Coil\",\n", " material=\"Copper (Annealed)_65C\",\n", ")\n", "coil_id.color = (255, 128, 0)\n", "m2d.modeler.rotate(assignment=coil_id, axis=\"Z\", angle=\"360deg/SlotNumber/2\")\n", "coil_id.duplicate_around_axis(\n", " axis=\"Z\", angle=\"360deg/SlotNumber\", clones=\"CoilPitch+1\", create_new_objects=True\n", ")\n", "id_coils = m2d.modeler.get_objects_w_string(string_name=\"Coil\", case_sensitive=True)" ] }, { "cell_type": "markdown", "id": "7e25f9e3", "metadata": {}, "source": [ "## Create shaft and region" ] }, { "cell_type": "code", "execution_count": null, "id": "2e331e3e", "metadata": {}, "outputs": [], "source": [ "region_id = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"DiaOuter/2\",\n", " num_sides=\"SegAngle\",\n", " is_covered=True,\n", " name=\"Region\",\n", ")\n", "shaft_id = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"DiaShaft/2\",\n", " num_sides=\"SegAngle\",\n", " is_covered=True,\n", " name=\"Shaft\",\n", ")" ] }, { "cell_type": "markdown", "id": "ad2f5b04", "metadata": {}, "source": [ "## Create bands\n", "\n", "Create the inner band, band, and outer band." ] }, { "cell_type": "code", "execution_count": null, "id": "3787815c", "metadata": {}, "outputs": [], "source": [ "bandIN_id = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"(DiaGap - (1.5 * Airgap))/2\",\n", " num_sides=\"mapping_angle\",\n", " is_covered=True,\n", " name=\"Inner_Band\",\n", ")\n", "bandMID_id = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"(DiaGap - (1.0 * Airgap))/2\",\n", " num_sides=\"mapping_angle\",\n", " is_covered=True,\n", " name=\"Band\",\n", ")\n", "bandOUT_id = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"(DiaGap - (0.5 * Airgap))/2\",\n", " num_sides=\"mapping_angle\",\n", " is_covered=True,\n", " name=\"Outer_Band\",\n", ")" ] }, { "cell_type": "markdown", "id": "12422c78", "metadata": {}, "source": [ "## Assign motion setup to object\n", "\n", "Assign a motion setup to a ``Band`` object named ``RotatingBand_mid``." ] }, { "cell_type": "code", "execution_count": null, "id": "0336fb38", "metadata": {}, "outputs": [], "source": [ "m2d.assign_rotate_motion(\n", " assignment=\"Band\",\n", " coordinate_system=\"Global\",\n", " axis=\"Z\",\n", " positive_movement=True,\n", " start_position=\"InitialPositionMD\",\n", " angular_velocity=\"MachineRPM\",\n", ")" ] }, { "cell_type": "markdown", "id": "d13c5730", "metadata": {}, "source": [ "## Create list of vacuum objects\n", "\n", "Create a list of vacuum objects and assign color." ] }, { "cell_type": "code", "execution_count": null, "id": "657277fd", "metadata": {}, "outputs": [], "source": [ "vacuum_obj_id = [\n", " shaft_id,\n", " region_id,\n", " bandIN_id,\n", " bandMID_id,\n", " bandOUT_id,\n", "] # put shaft first\n", "for item in vacuum_obj_id:\n", " item.color = (128, 255, 255)" ] }, { "cell_type": "markdown", "id": "f8c2bf78", "metadata": {}, "source": [ "## Create rotor\n", "\n", "Create the rotor. Holes are specific to the lamination.\n", "Allocated PMs are created." ] }, { "cell_type": "code", "execution_count": null, "id": "218d8bd6", "metadata": {}, "outputs": [], "source": [ "rotor_id = m2d.modeler.create_circle(\n", " origin=[0, 0, 0],\n", " radius=\"DiaRotorLam/2\",\n", " num_sides=0,\n", " name=\"Rotor\",\n", " material=\"30DH_20C_smooth\",\n", ")\n", "\n", "rotor_id.color = (0, 128, 255)\n", "m2d.modeler.subtract(blank_list=rotor_id, tool_list=shaft_id, keep_originals=True)\n", "void_small_1_id = m2d.modeler.create_circle(\n", " origin=[62, 0, 0], radius=\"2.55mm\", num_sides=0, name=\"void1\", material=\"vacuum\"\n", ")\n", "\n", "m2d.modeler.duplicate_around_axis(\n", " assignment=void_small_1_id,\n", " axis=\"Z\",\n", " angle=\"360deg/SymmetryFactor\",\n", " clones=2,\n", " create_new_objects=False,\n", ")\n", "\n", "void_big_1_id = m2d.modeler.create_circle(\n", " origin=[29.5643, 12.234389332712, 0],\n", " radius=\"9.88mm/2\",\n", " num_sides=0,\n", " name=\"void_big\",\n", " material=\"vacuum\",\n", ")\n", "m2d.modeler.subtract(\n", " blank_list=rotor_id,\n", " tool_list=[void_small_1_id, void_big_1_id],\n", " keep_originals=False,\n", ")\n", "\n", "slot_IM1_points = [\n", " [37.5302872, 15.54555396, 0],\n", " [55.05576774, 1.098662669, 0],\n", " [57.33637589, 1.25, 0],\n", " [57.28982158, 2.626565019, 0],\n", " [40.25081875, 16.67243502, 0],\n", "]\n", "slot_OM1_points = [\n", " [54.37758185, 22.52393189, 0],\n", " [59.69688156, 9.68200639, 0],\n", " [63.53825619, 10.5, 0],\n", " [57.94560461, 24.00185531, 0],\n", "]\n", "slot_IM_id = m2d.modeler.create_polyline(\n", " points=slot_IM1_points, cover_surface=True, name=\"slot_IM1\", material=\"vacuum\"\n", ")\n", "slot_OM_id = m2d.modeler.create_polyline(\n", " points=slot_OM1_points, cover_surface=True, name=\"slot_OM1\", material=\"vacuum\"\n", ")\n", "\n", "m2d.modeler.duplicate_and_mirror(\n", " assignment=[slot_IM_id, slot_OM_id],\n", " origin=[0, 0, 0],\n", " vector=[\n", " \"cos((360deg/SymmetryFactor/2)+90deg)\",\n", " \"sin((360deg/SymmetryFactor/2)+90deg)\",\n", " 0,\n", " ],\n", ")\n", "\n", "id_holes = m2d.modeler.get_objects_w_string(string_name=\"slot_\", case_sensitive=True)\n", "m2d.modeler.subtract(rotor_id, id_holes, keep_originals=True)" ] }, { "cell_type": "markdown", "id": "1564bbec", "metadata": {}, "source": [ "## Create section of machine\n", "\n", "Create a section of the machine. This allows you to take\n", "advantage of symmetries." ] }, { "cell_type": "code", "execution_count": null, "id": "63485ac1", "metadata": {}, "outputs": [], "source": [ "object_list = [stator_id, rotor_id] + vacuum_obj_id\n", "m2d.modeler.create_coordinate_system(\n", " origin=[0, 0, 0],\n", " reference_cs=\"Global\",\n", " name=\"Section\",\n", " mode=\"axis\",\n", " x_pointing=[\"cos(360deg/SymmetryFactor)\", \"sin(360deg/SymmetryFactor)\", 0],\n", " y_pointing=[\"-sin(360deg/SymmetryFactor)\", \"cos(360deg/SymmetryFactor)\", 0],\n", ")\n", "\n", "m2d.modeler.set_working_coordinate_system(\"Section\")\n", "m2d.modeler.split(assignment=object_list, plane=\"ZX\", sides=\"NegativeOnly\")\n", "m2d.modeler.set_working_coordinate_system(\"Global\")\n", "m2d.modeler.split(assignment=object_list, plane=\"ZX\", sides=\"PositiveOnly\")" ] }, { "cell_type": "markdown", "id": "8b2c1974", "metadata": {}, "source": [ "## Create boundary conditions\n", "\n", "Create independent and dependent boundary conditions.\n", "Edges for assignment are picked by position.\n", "The points for edge picking are in the airgap." ] }, { "cell_type": "code", "execution_count": null, "id": "ac4cf540", "metadata": {}, "outputs": [], "source": [ "pos_1 = \"((DiaGap - (1.0 * Airgap))/4)\"\n", "id_bc_1 = m2d.modeler.get_edgeid_from_position(\n", " position=[pos_1, 0, 0], assignment=\"Region\"\n", ")\n", "id_bc_2 = m2d.modeler.get_edgeid_from_position(\n", " position=[\n", " pos_1 + \"*cos((360deg/SymmetryFactor))\",\n", " pos_1 + \"*sin((360deg/SymmetryFactor))\",\n", " 0,\n", " ],\n", " assignment=\"Region\",\n", ")\n", "m2d.assign_master_slave(\n", " independent=id_bc_1,\n", " dependent=id_bc_2,\n", " reverse_master=False,\n", " reverse_slave=True,\n", " same_as_master=False,\n", " boundary=\"Matching\",\n", ")" ] }, { "cell_type": "markdown", "id": "c9aec989", "metadata": {}, "source": [ "## Assign vector potential\n", "\n", "Assign a vector potential of ``0`` to the second position." ] }, { "cell_type": "code", "execution_count": null, "id": "d4c7865f", "metadata": {}, "outputs": [], "source": [ "pos_2 = \"(DiaOuter/2)\"\n", "id_bc_az = m2d.modeler.get_edgeid_from_position(\n", " position=[\n", " pos_2 + \"*cos((360deg/SymmetryFactor/2))\",\n", " pos_2 + \"*sin((360deg/SymmetryFactor)/2)\",\n", " 0,\n", " ],\n", " assignment=\"Region\",\n", ")\n", "m2d.assign_vector_potential(\n", " assignment=id_bc_az, vector_value=0, boundary=\"VectorPotentialZero\"\n", ")" ] }, { "cell_type": "markdown", "id": "c59206e4", "metadata": {}, "source": [ "## Create excitations\n", "\n", "Create excitations, defining phase currents for the windings." ] }, { "cell_type": "code", "execution_count": null, "id": "c715a2d8", "metadata": {}, "outputs": [], "source": [ "ph_a_current = \"IPeak * cos(2*pi*ElectricFrequency*time+Theta_i)\"\n", "ph_b_current = \"IPeak * cos(2*pi * ElectricFrequency*time - 120deg+Theta_i)\"\n", "ph_c_current = \"IPeak * cos(2*pi * ElectricFrequency*time - 240deg+Theta_i)\"" ] }, { "cell_type": "markdown", "id": "133077ad", "metadata": {}, "source": [ "## Define windings in phase A" ] }, { "cell_type": "code", "execution_count": null, "id": "eb36c71e", "metadata": {}, "outputs": [], "source": [ "m2d.assign_coil(\n", " assignment=[\"Coil\"],\n", " conductors_number=6,\n", " polarity=\"Positive\",\n", " name=\"CT_Ph1_P2_C1_Go\",\n", ")\n", "m2d.assign_coil(\n", " assignment=[\"Coil_5\"],\n", " conductors_number=6,\n", " polarity=\"Negative\",\n", " name=\"CT_Ph1_P2_C1_Ret\",\n", ")\n", "m2d.assign_winding(\n", " assignment=None,\n", " winding_type=\"Current\",\n", " is_solid=False,\n", " current=ph_a_current,\n", " parallel_branches=1,\n", " name=\"Phase_A\",\n", ")\n", "m2d.add_winding_coils(\n", " assignment=\"Phase_A\", coils=[\"CT_Ph1_P2_C1_Go\", \"CT_Ph1_P2_C1_Ret\"]\n", ")" ] }, { "cell_type": "markdown", "id": "b6e1fce4", "metadata": {}, "source": [ "## Define windings in phase B" ] }, { "cell_type": "code", "execution_count": null, "id": "1573f557", "metadata": {}, "outputs": [], "source": [ "m2d.assign_coil(\n", " assignment=\"Coil_3\",\n", " conductors_number=6,\n", " polarity=\"Positive\",\n", " name=\"CT_Ph3_P1_C2_Go\",\n", ")\n", "m2d.assign_coil(\n", " assignment=\"Coil_4\",\n", " conductors_number=6,\n", " polarity=\"Positive\",\n", " name=\"CT_Ph3_P1_C1_Go\",\n", ")\n", "m2d.assign_winding(\n", " assignment=None,\n", " winding_type=\"Current\",\n", " is_solid=False,\n", " current=ph_b_current,\n", " parallel_branches=1,\n", " name=\"Phase_B\",\n", ")\n", "m2d.add_winding_coils(\n", " assignment=\"Phase_B\", coils=[\"CT_Ph3_P1_C2_Go\", \"CT_Ph3_P1_C1_Go\"]\n", ")" ] }, { "cell_type": "markdown", "id": "21cedba2", "metadata": {}, "source": [ "## Define windings in phase C" ] }, { "cell_type": "code", "execution_count": null, "id": "9cb6cf2d", "metadata": {}, "outputs": [], "source": [ "m2d.assign_coil(\n", " assignment=\"Coil_1\",\n", " conductors_number=6,\n", " polarity=\"Negative\",\n", " name=\"CT_Ph2_P2_C2_Ret\",\n", ")\n", "m2d.assign_coil(\n", " assignment=\"Coil_2\",\n", " conductors_number=6,\n", " polarity=\"Negative\",\n", " name=\"CT_Ph2_P2_C1_Ret\",\n", ")\n", "m2d.assign_winding(\n", " assignment=None,\n", " winding_type=\"Current\",\n", " is_solid=False,\n", " current=ph_c_current,\n", " parallel_branches=1,\n", " name=\"Phase_C\",\n", ")\n", "m2d.add_winding_coils(\n", " assignment=\"Phase_C\", coils=[\"CT_Ph2_P2_C2_Ret\", \"CT_Ph2_P2_C1_Ret\"]\n", ")" ] }, { "cell_type": "markdown", "id": "29c86b0f", "metadata": {}, "source": [ "## Assign total current on PMs\n", "\n", "Assign a total current of ``0`` on the PMs." ] }, { "cell_type": "code", "execution_count": null, "id": "62d2e693", "metadata": {}, "outputs": [], "source": [ "PM_list = id_PMs\n", "for item in PM_list:\n", " m2d.assign_current(assignment=item, amplitude=0, solid=True, name=item + \"_I0\")" ] }, { "cell_type": "markdown", "id": "d17e9c6c", "metadata": {}, "source": [ "## Create mesh operations" ] }, { "cell_type": "code", "execution_count": null, "id": "c23848e8", "metadata": {}, "outputs": [], "source": [ "m2d.mesh.assign_length_mesh(\n", " assignment=id_coils,\n", " inside_selection=True,\n", " maximum_length=3,\n", " maximum_elements=None,\n", " name=\"coils\",\n", ")\n", "m2d.mesh.assign_length_mesh(\n", " assignment=stator_id,\n", " inside_selection=True,\n", " maximum_length=3,\n", " maximum_elements=None,\n", " name=\"stator\",\n", ")\n", "m2d.mesh.assign_length_mesh(\n", " assignment=rotor_id,\n", " inside_selection=True,\n", " maximum_length=3,\n", " maximum_elements=None,\n", " name=\"rotor\",\n", ")" ] }, { "cell_type": "markdown", "id": "01fb2adc", "metadata": {}, "source": [ "## Turn on core loss" ] }, { "cell_type": "code", "execution_count": null, "id": "0a0b2c15", "metadata": {}, "outputs": [], "source": [ "core_loss_list = [\"Rotor\", \"Stator\"]\n", "m2d.set_core_losses(core_loss_list, core_loss_on_field=True)" ] }, { "cell_type": "markdown", "id": "8f61f387", "metadata": {}, "source": [ "## Compute transient inductance" ] }, { "cell_type": "code", "execution_count": null, "id": "f9fc3c22", "metadata": {}, "outputs": [], "source": [ "m2d.change_inductance_computation(\n", " compute_transient_inductance=True, incremental_matrix=False\n", ")" ] }, { "cell_type": "markdown", "id": "8933a980", "metadata": {}, "source": [ "## Set model depth" ] }, { "cell_type": "code", "execution_count": null, "id": "efb81757", "metadata": {}, "outputs": [], "source": [ "m2d.model_depth = \"Magnetic_Axial_Length\"" ] }, { "cell_type": "markdown", "id": "87c81ed2", "metadata": {}, "source": [ "## Set symmetry factor" ] }, { "cell_type": "code", "execution_count": null, "id": "62835793", "metadata": {}, "outputs": [], "source": [ "m2d.change_symmetry_multiplier(\"SymmetryFactor\")" ] }, { "cell_type": "markdown", "id": "6aa57f39", "metadata": {}, "source": [ "## Create setup and validate" ] }, { "cell_type": "code", "execution_count": null, "id": "6b2295ef", "metadata": {}, "outputs": [], "source": [ "setup_name = \"MySetupAuto\"\n", "setup = m2d.create_setup(name=setup_name)\n", "setup.props[\"StopTime\"] = \"StopTime\"\n", "setup.props[\"TimeStep\"] = \"TimeStep\"\n", "setup.props[\"SaveFieldsType\"] = \"None\"\n", "setup.props[\"OutputPerObjectCoreLoss\"] = True\n", "setup.props[\"OutputPerObjectSolidLoss\"] = True\n", "setup.props[\"OutputError\"] = True\n", "setup.update()\n", "m2d.validate_simple()\n", "\n", "model = m2d.plot(show=False)\n", "model.plot(os.path.join(temp_folder.name, \"Image.jpg\"))" ] }, { "cell_type": "markdown", "id": "200a217b", "metadata": {}, "source": [ "## Initialize definitions for output variables\n", "\n", "Initialize the definitions for the output variables.\n", "These are used later to generate reports." ] }, { "cell_type": "code", "execution_count": null, "id": "0e1d94a6", "metadata": {}, "outputs": [], "source": [ "output_vars = {\n", " \"Current_A\": \"InputCurrent(Phase_A)\",\n", " \"Current_B\": \"InputCurrent(Phase_B)\",\n", " \"Current_C\": \"InputCurrent(Phase_C)\",\n", " \"Flux_A\": \"FluxLinkage(Phase_A)\",\n", " \"Flux_B\": \"FluxLinkage(Phase_B)\",\n", " \"Flux_C\": \"FluxLinkage(Phase_C)\",\n", " \"pos\": \"(Moving1.Position -InitialPositionMD) *NumPoles/2\",\n", " \"cos0\": \"cos(pos)\",\n", " \"cos1\": \"cos(pos-2*PI/3)\",\n", " \"cos2\": \"cos(pos-4*PI/3)\",\n", " \"sin0\": \"sin(pos)\",\n", " \"sin1\": \"sin(pos-2*PI/3)\",\n", " \"sin2\": \"sin(pos-4*PI/3)\",\n", " \"Flux_d\": \"2/3*(Flux_A*cos0+Flux_B*cos1+Flux_C*cos2)\",\n", " \"Flux_q\": \"-2/3*(Flux_A*sin0+Flux_B*sin1+Flux_C*sin2)\",\n", " \"I_d\": \"2/3*(Current_A*cos0 + Current_B*cos1 + Current_C*cos2)\",\n", " \"I_q\": \"-2/3*(Current_A*sin0 + Current_B*sin1 + Current_C*sin2)\",\n", " \"Irms\": \"sqrt(I_d^2+I_q^2)/sqrt(2)\",\n", " \"ArmatureOhmicLoss_DC\": \"Irms^2*R_phase\",\n", " \"Lad\": \"L(Phase_A,Phase_A)*cos0 + L(Phase_A,Phase_B)*cos1 + L(Phase_A,Phase_C)*cos2\",\n", " \"Laq\": \"L(Phase_A,Phase_A)*sin0 + L(Phase_A,Phase_B)*sin1 + L(Phase_A,Phase_C)*sin2\",\n", " \"Lbd\": \"L(Phase_B,Phase_A)*cos0 + L(Phase_B,Phase_B)*cos1 + L(Phase_B,Phase_C)*cos2\",\n", " \"Lbq\": \"L(Phase_B,Phase_A)*sin0 + L(Phase_B,Phase_B)*sin1 + L(Phase_B,Phase_C)*sin2\",\n", " \"Lcd\": \"L(Phase_C,Phase_A)*cos0 + L(Phase_C,Phase_B)*cos1 + L(Phase_C,Phase_C)*cos2\",\n", " \"Lcq\": \"L(Phase_C,Phase_A)*sin0 + L(Phase_C,Phase_B)*sin1 + L(Phase_C,Phase_C)*sin2\",\n", " \"L_d\": \"(Lad*cos0 + Lbd*cos1 + Lcd*cos2) * 2/3\",\n", " \"L_q\": \"(Laq*sin0 + Lbq*sin1 + Lcq*sin2) * 2/3\",\n", " \"OutputPower\": \"Moving1.Speed*Moving1.Torque\",\n", " \"Ui_A\": \"InducedVoltage(Phase_A)\",\n", " \"Ui_B\": \"InducedVoltage(Phase_B)\",\n", " \"Ui_C\": \"InducedVoltage(Phase_C)\",\n", " \"Ui_d\": \"2/3*(Ui_A*cos0 + Ui_B*cos1 + Ui_C*cos2)\",\n", " \"Ui_q\": \"-2/3*(Ui_A*sin0 + Ui_B*sin1 + Ui_C*sin2)\",\n", " \"U_A\": \"Ui_A+R_Phase*Current_A\",\n", " \"U_B\": \"Ui_B+R_Phase*Current_B\",\n", " \"U_C\": \"Ui_C+R_Phase*Current_C\",\n", " \"U_d\": \"2/3*(U_A*cos0 + U_B*cos1 + U_C*cos2)\",\n", " \"U_q\": \"-2/3*(U_A*sin0 + U_B*sin1 + U_C*sin2)\",\n", "}" ] }, { "cell_type": "markdown", "id": "b3e8fd71", "metadata": {}, "source": [ "## Create output variables for postprocessing" ] }, { "cell_type": "code", "execution_count": null, "id": "ee87d0a5", "metadata": {}, "outputs": [], "source": [ "for k, v in output_vars.items():\n", " m2d.create_output_variable(k, v)" ] }, { "cell_type": "markdown", "id": "1977a99d", "metadata": {}, "source": [ "## Initialize definition for postprocessing plots" ] }, { "cell_type": "code", "execution_count": null, "id": "1cbc983d", "metadata": {}, "outputs": [], "source": [ "post_params = {\"Moving1.Torque\": \"TorquePlots\"}" ] }, { "cell_type": "markdown", "id": "b4874f0a", "metadata": {}, "source": [ "## Initialize definition for postprocessing multiplots" ] }, { "cell_type": "code", "execution_count": null, "id": "64084f40", "metadata": {}, "outputs": [], "source": [ "post_params_multiplot = { # reports\n", " (\"U_A\", \"U_B\", \"U_C\", \"Ui_A\", \"Ui_B\", \"Ui_C\"): \"PhaseVoltages\",\n", " (\"CoreLoss\", \"SolidLoss\", \"ArmatureOhmicLoss_DC\"): \"Losses\",\n", " (\n", " \"InputCurrent(Phase_A)\",\n", " \"InputCurrent(Phase_B)\",\n", " \"InputCurrent(Phase_C)\",\n", " ): \"PhaseCurrents\",\n", " (\n", " \"FluxLinkage(Phase_A)\",\n", " \"FluxLinkage(Phase_B)\",\n", " \"FluxLinkage(Phase_C)\",\n", " ): \"PhaseFluxes\",\n", " (\"I_d\", \"I_q\"): \"Currents_dq\",\n", " (\"Flux_d\", \"Flux_q\"): \"Fluxes_dq\",\n", " (\"Ui_d\", \"Ui_q\"): \"InducedVoltages_dq\",\n", " (\"U_d\", \"U_q\"): \"Voltages_dq\",\n", " (\n", " \"L(Phase_A,Phase_A)\",\n", " \"L(Phase_B,Phase_B)\",\n", " \"L(Phase_C,Phase_C)\",\n", " \"L(Phase_A,Phase_B)\",\n", " \"L(Phase_A,Phase_C)\",\n", " \"L(Phase_B,Phase_C)\",\n", " ): \"PhaseInductances\",\n", " (\"L_d\", \"L_q\"): \"Inductances_dq\",\n", " (\"CoreLoss\", \"CoreLoss(Stator)\", \"CoreLoss(Rotor)\"): \"CoreLosses\",\n", " (\n", " \"EddyCurrentLoss\",\n", " \"EddyCurrentLoss(Stator)\",\n", " \"EddyCurrentLoss(Rotor)\",\n", " ): \"EddyCurrentLosses (Core)\",\n", " (\"ExcessLoss\", \"ExcessLoss(Stator)\", \"ExcessLoss(Rotor)\"): \"ExcessLosses (Core)\",\n", " (\n", " \"HysteresisLoss\",\n", " \"HysteresisLoss(Stator)\",\n", " \"HysteresisLoss(Rotor)\",\n", " ): \"HysteresisLosses (Core)\",\n", " (\n", " \"SolidLoss\",\n", " \"SolidLoss(IPM1)\",\n", " \"SolidLoss(IPM1_1)\",\n", " \"SolidLoss(OPM1)\",\n", " \"SolidLoss(OPM1_1)\",\n", " ): \"SolidLoss\",\n", "}" ] }, { "cell_type": "markdown", "id": "78f56a3f", "metadata": {}, "source": [ "## Create report." ] }, { "cell_type": "code", "execution_count": null, "id": "99877bb0", "metadata": {}, "outputs": [], "source": [ "for k, v in post_params.items():\n", " m2d.post.create_report(\n", " expressions=k,\n", " setup_sweep_name=\"\",\n", " domain=\"Sweep\",\n", " variations=None,\n", " primary_sweep_variable=\"Time\",\n", " secondary_sweep_variable=None,\n", " report_category=None,\n", " plot_type=\"Rectangular Plot\",\n", " context=None,\n", " subdesign_id=None,\n", " polyline_points=1001,\n", " plot_name=v,\n", " )" ] }, { "cell_type": "markdown", "id": "5f07dc04", "metadata": {}, "source": [ "## Create multiplot report" ] }, { "cell_type": "code", "execution_count": null, "id": "0b1cbb72", "metadata": {}, "outputs": [], "source": [ "# for k, v in post_params_multiplot.items():\n", "# m2d.post.create_report(expressions=list(k), setup_sweep_name=\"\",\n", "# domain=\"Sweep\", variations=None,\n", "# primary_sweep_variable=\"Time\", secondary_sweep_variable=None,\n", "# report_category=None, plot_type=\"Rectangular Plot\",\n", "# context=None, subdesign_id=None,\n", "# polyline_points=1001, plotname=v)" ] }, { "cell_type": "markdown", "id": "3610e421", "metadata": {}, "source": [ "## Analyze and save project" ] }, { "cell_type": "code", "execution_count": null, "id": "791f9f2f", "metadata": {}, "outputs": [], "source": [ "m2d.save_project()\n", "m2d.analyze_setup(setup_name, use_auto_settings=False, cores=NUM_CORES)" ] }, { "cell_type": "markdown", "id": "8dc3a09b", "metadata": {}, "source": [ "## Create flux lines plot on region\n", "\n", "Create a flux lines plot on a region. The ``object_list`` is\n", "formerly created when the section is applied." ] }, { "cell_type": "code", "execution_count": null, "id": "d43fd2d6", "metadata": {}, "outputs": [], "source": [ "faces_reg = m2d.modeler.get_object_faces(object_list[1].name) # Region\n", "plot1 = m2d.post.create_fieldplot_surface(\n", " assignment=faces_reg,\n", " quantity=\"Flux_Lines\",\n", " intrinsics={\"Time\": m2d.variable_manager.variables[\"StopTime\"].evaluated_value},\n", " plot_name=\"Flux_Lines\",\n", ")" ] }, { "cell_type": "markdown", "id": "5221daef", "metadata": {}, "source": [ "## Export a field plot to an image file\n", "\n", "Export the flux lines plot to an image file using Python PyVista." ] }, { "cell_type": "code", "execution_count": null, "id": "fa99920e", "metadata": {}, "outputs": [], "source": [ "m2d.post.plot_field_from_fieldplot(plot1.name, show=False)" ] }, { "cell_type": "markdown", "id": "07db195f", "metadata": {}, "source": [ "## Get solution data\n", "\n", "Get a simulation result from a solved setup and cast it in a ``SolutionData`` object.\n", "Plot the desired expression by using the Matplotlib ``plot()`` function." ] }, { "cell_type": "code", "execution_count": null, "id": "b6d81887", "metadata": {}, "outputs": [], "source": [ "solutions = m2d.post.get_solution_data(\n", " expressions=\"Moving1.Torque\", primary_sweep_variable=\"Time\"\n", ")\n", "# solutions.plot()" ] }, { "cell_type": "markdown", "id": "2c49d937", "metadata": {}, "source": [ "## Retrieve the data magnitude of an expression\n", "\n", "List of shaft torque points and compute average." ] }, { "cell_type": "code", "execution_count": null, "id": "418bb54c", "metadata": {}, "outputs": [], "source": [ "mag = solutions.data_magnitude()\n", "avg = sum(mag) / len(mag)" ] }, { "cell_type": "markdown", "id": "70bf6931", "metadata": {}, "source": [ "## Export a report to a file\n", "\n", "Export 2D plot data to a CSV file." ] }, { "cell_type": "code", "execution_count": null, "id": "31fb9b5b", "metadata": {}, "outputs": [], "source": [ "m2d.post.export_report_to_file(\n", " output_dir=temp_folder.name, plot_name=\"TorquePlots\", extension=\".csv\"\n", ")" ] }, { "cell_type": "markdown", "id": "5d2644f5", "metadata": {}, "source": [ "## Release AEDT" ] }, { "cell_type": "code", "execution_count": null, "id": "558b8e70", "metadata": {}, "outputs": [], "source": [ "m2d.save_project()\n", "m2d.release_desktop()\n", "# Wait 3 seconds to allow AEDT to shut down before cleaning the temporary directory.\n", "time.sleep(3)" ] }, { "cell_type": "markdown", "id": "1df5b422", "metadata": {}, "source": [ "## Clean up\n", "\n", "All project files are saved in the folder ``temp_folder.name``.\n", "If you've run this example as a Jupyter notebook, you\n", "can retrieve those project files. The following cell\n", "removes all temporary files, including the project folder." ] }, { "cell_type": "code", "execution_count": null, "id": "039dcaa2", "metadata": {}, "outputs": [], "source": [ "temp_folder.cleanup()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "main_language": "python", "notebook_metadata_filter": "-all" } }, "nbformat": 4, "nbformat_minor": 5 }