# Geometry Tutorial 2: (Almost) Creating a Rotor Template

In this tutorial, you will *almost* learn how to create a geometry template for the rotor of a simple switched reluctance motor (SRM). (Indeed, the geometry will be fully usable, just not encapsulated inside its own Matlab class).

Along the journey, we will also learn some other useful items:

## Contents

## Initializing dimensions

We begin by collecting the important dimensions inside a Matlab struct. Why? This allows us to collect all rotor-related dimensions under a single Matlab variable. Furthermore, turning this script into a function later is then much easier.

Now, let's skip to the business and set some dimensions:

dimensions = struct(); dimensions.Rout = 50e-3; %outer diameter of our rotor dimensions.Qr = 6; %number of rotor teeth dimensions.w_tooth_r_out = 18e-3; %tooth tip width dimensions.w_tooth_r_in = 21e-3; %tooth width near rotor yoke dimensions.h_tooth_r = 20e-3; %tooth height

As can be seen, our simple rotor geometry is fully determined by only a few dimensions:

- Its outer radius (or diameter, whichever you prefer)
- Number of poles
- The height of the rotor tooth, and its width at the top and bottom

## Creating the tooth tip

We begin by creating the tip of the rotor tooth. First, let us assume we have a single rotor tooth laying centered on the x-axis. Next, we create a Point to represented the counter-clockwise corner of the tooth tip:

```
pout_clockwise = Point([sqrt(dimensions.Rout^2-(dimensions.w_tooth_r_out/2)^2), ...
-dimensions.w_tooth_r_out/2], 1e-3);
```

Note how the x-coordinate of the Point is not exactly *dimensions.Rout*. Instead, it's somewhat smaller according to the Pythagorean theorem to maintain the correct airgap radius:

norm(pout_clockwise) - dimensions.Rout

ans = 0

However, the *recommended* way of creating rotor pole shapes for `EMDtool` is **not** to have the pole d-axis centered along the x-axis.

Instead, the geometry should be rotated by one half of the pole pitch.

Let us do that now for the point we just created, and plot it before and after the rotation:

figure(1); clf; hold on; box on; axis equal; pout_clockwise.plot('pout-clockwise', 'ko'); %plot before rotation %rotation: pout_clockwise = pout_clockwise.rotate( pi/dimensions.Qr ); %pout_clockwise.rotate_inplace( pi/dimensions.Qr ); %this would also work pout_clockwise.plot('pout-clockwise after rotation', 'mo'); %plot after rotation snapnow;

Finally, to create the counter-clockwise equivalent of the tooth-tip corner point, we use the *mirror* function of the Point class:

pout_counterclockwise = pout_clockwise.mirror( 2*pi/dimensions.Qr );

Like stated in the documentation, this method mirrors the point around the *center* of the segment with a width of 2*pi/dimensions.Qr radians. For reference, let's plot both the original point and the mirrored one, and the segment centerline:

clf; hold on; box on; set(gca, 'XLim', [0 dimensions.Rout*1.5]); daspect([1 1 1]); pout_clockwise.plot('Original point', 'mo'); %plot after rotation pout_counterclockwise.plot('Mirrored point', 'ro'); plot([0 dimensions.Rout*cos(pi/dimensions.Qr)], [0 dimensions.Rout*sin(pi/dimensions.Qr)], 'k--');

## Creating the tooth body and rotor core

Next, let's create the points for the tooth bottom, and the rotor core.

r_in = dimensions.Rout - dimensions.h_tooth_r; %radial coordinate of tooth bottom pin_clockwise = Point([sqrt(r_in^2-(dimensions.w_tooth_r_in/2)^2), ... -dimensions.w_tooth_r_in/2], 5e-3).rotate( pi/dimensions.Qr ); pin_counterclockwise = pin_clockwise.mirror( 2*pi/dimensions.Qr ); p_core_cw = Point( [r_in, 0], 10e-3); p_core_ccw = p_core_cw.mirror( 2*pi/dimensions.Qr );

Finally, let's create a Surface object.

O = Point([0,0], 10e-3); s_core = Surface('core', ... geo.line, O, p_core_cw, 'n_cw', ... geo.arc, p_core_cw, O, pin_clockwise, ... geo.line, pin_clockwise, pout_clockwise, ... geo.arc, pout_clockwise, O, pout_counterclockwise, 'n_ag', ... geo.line, pout_counterclockwise, pin_counterclockwise, ... geo.arc, pin_counterclockwise, O, p_core_ccw, ... geo.line, p_core_ccw, O, 'n_ccw');

we set the boundary lines as periodic, to allow mesh replication and periodic boundary conditions:

geo.set_periodic(O, p_core_cw, O, p_core_ccw);

Visualize the surface and points for clarity:

s_core.plot('k'); O.plot('Origin', 'ko'); pin_clockwise.plot('pin-clockwise', 'ko'); pin_counterclockwise.plot('pin-counterclockwise', 'ko'); p_core_cw.plot('p-core-cw', 'ms'); p_core_ccw.plot('p-core-ccw', 'ms');

Now, note that while defining the Surface, we used quite a many named Curves:

`n_cw`for the clockwise*periodic boundary*`n_ccw`for the counter-clockwise boundary`n_ag`for the airgap surface

We'll see later that by defining these Curves, with these *exact* names, many boring and error-prone tasks can be handled automatically:

- replicating a pole or slot segment of a radial-flux machine
- setting periodic boundary conditions of analysis
- setting up an interface for modelling motion

UPDATE (3.0.1): geo.set_periodic method now does the naming `(n_cw, n_ccw)` automatically.

## Creating a Geometry object

Next, we demonstrate several classes used for creating and analysing finite element models:

We begin by first defining some parameters necessary for mesh replication

```
dimensions.Nrep = 3; %we are not replicating the mesh here
dimensions.sector_angle = 2*pi/dimensions.Qr;
```

and then initializing the RadialGeometry object:

```
rotor = RadialGeometry(dimensions) %Geometry objects
```

rotor = RadialGeometry with properties: mesh: [] p: [] t: [] n_dir: [] n_cw: [] n_ccw: [] n_ag: [] edges: [1×1 struct] boundaries: [1×1 struct] circuits: [] data: [1×1 struct] domains: [] materials: [] PMs: [] name: '' dimensions: [1×1 struct] parent: []

As can be seen, the class has quite a few interesting properties like:

`p`and`t`: for nodes and triangles respectively, suggesting it is indeed a*mesh*`materials`,`domains`,`circuits`, and`PMs`that we'll take a look at next`n_cw`,`n_ccw`,`n_ag`, and`n_dir`that we'll take a brief look on at the end of this tutorial.

Next, we create a Material object for the rotor iron.

Iron = Material.create(4);

Similarly, we create Domain object for representing the rotor core.

```
Core = Domain('Core', Iron, s_core);
```

Despite their apparent similarity, Domain objects are entirely different from Surface objects. Indeed, Surface objects

- are intended for representing surfaces
*before*meshing - are defined by their boundary alone.

By contrast, Domain objects

- consist of
*meshed*surfaces - may consist of one or more Surfaces ...
- represent interesting parts of the motor
- consist of a single Material
- may have a
*remanence direction*(in case of PMs) - may have an
*orientation*(in case of anisotropic materials) - may belong to a Circuit
- may contain additional data in
*domain*.data struct

Next, we add the materials and domains to the geometry:

rotor.add_material(Iron); rotor.add_domain(Core);

## Meshing the geometry object

Finally, it is time to mesh the geometry.

rotor.mesh_elementary_geometry(); clf; hold on; box on; axis equal; rotor.triplot('k');

Next, we replicate the mesh to cover the entire *symmetry sector*:

rotor.replicate_elementary_mesh( ) clf; hold on; box on; axis equal; rotor.triplot('k');

## Adding polegap domains

Obviously, our rotor model is not yet complete. Indeed, we need to add some air between the rotor tooth.

This follows exactly the same approach as before, beginning with defining the desired Points and Surfaces.

p_air_cw = Point([dimensions.Rout, 0], 1e-3); p_air_ccw = p_air_cw.mirror( 2*pi/dimensions.Qr ); s_air_cw = Surface('air', ... geo.line, p_core_cw, p_air_cw, 'n_cw', ... geo.arc, p_air_cw, O, pout_clockwise, 'n_ag', ... geo.line, pout_clockwise, pin_clockwise, ... geo.arc, pin_clockwise, O, p_core_cw); s_air_ccw = Surface('air', ... geo.line, p_core_ccw, p_air_ccw, 'n_ccw', ... geo.arc, p_air_ccw, O, pout_counterclockwise, 'n_ag', ... geo.line, pout_counterclockwise, pin_counterclockwise, ... geo.arc, pin_counterclockwise, O, p_core_ccw); geo.set_periodic(p_core_cw, p_air_cw, p_core_ccw, p_air_ccw); clf; hold on; box on; axis equal; s_core.plot('k'); s_air_cw.plot('r', 'linewidth',2); s_air_ccw.plot('r', 'linewidth',2);

Next, it is turn to add the corresponding new Materials and Domains.

Note that we have to redefine the GeoBase object *rotor* here, as we can't be adding stuff to an already-meshed geometry.

rotor = RadialGeometry(dimensions); Air = Material.create(0); Core = Domain('Core', Iron, s_core); Polegap = Domain('Polegap', Air, s_air_cw, s_air_ccw); rotor.add_material(Iron, Air); rotor.add_domain(Core, Polegap);

Again, we create the elementary mesh...

rotor.mesh_elementary_geometry(); clf; hold on; box on; axis equal; rotor.triplot('Core', 'k'); rotor.triplot('Polegap', 'r');

and then replicate it to cover the symmetry sector.

rotor.replicate_elementary_mesh( )

## A Closer look at GeoBase

Earlier, we saw that after meshing the *elementary* geometry, it was easy to e.g. `triplot` the Core Domain by referring to its name 'Core'.

Under the hood, this calls, the `get_domain` method of GeoBase. However, after *replicating* the elementary mesh, the rotor domain names are a little different:

rotor.domains(1:4).name

ans = 'Core_1' ans = 'Polegap_1' ans = 'Core_2' ans = 'Polegap_2'

Indeed, each elementary *segment* of the replicated geometry now has its own Domain. Furthermore, the underscored number at the end of each domain name indicates which replicated sector it belongs to.

clf; hold on; box on; axis equal tight; rotor.fill('Core_1', [1 1 1]*0.3); rotor.fill('Core_2', [1 1 1]*0.5); snapnow

However, thanks to how `get_domain` is implemented, we can also use the asterisk (*) wildcard character to get all domains corresponding to the original one:

clf; hold on; box on; axis equal tight; rotor.fill('Core_*', [1 1 1]*0.65); rotor.fill('Polegap_*', 'y'); snapnow;

Finally, remember those special Curves we named while defining the Surfaces wayyy back above? Namely:

`n_cw`for the*clockwise*periodic boundary`n_ccw`for the*counter-clockwise*boundary`n_ag`for the*airgap*surface- (and
`n_dir`for Dirichlet / flux insulation, had we used any)?

Turns out, we can find the *nodes* of them all as properties of the Geometry object:

rotor.plot(rotor.n_cw, 'ro-', 'Linewidth', 2); rotor.plot(rotor.n_ccw, 'gd-', 'Linewidth', 2); rotor.plot(rotor.n_ag, 'bx-');

## What to read next?

Next, you'll learn how to use your newly-created geometries in actual analysis. You'll learn, for instance, how to calculate:

- Flux density maps
- Torque curve
- Iron and copper losses
- Torque waveform

All this, and much more, you'll learn in the Analysis Tutorial 1.

Well, you *will* as soon as the tutorial gets published. To receive an email update when it does, please fill out this really short single-page survey here.