8. SynR JMAG 2D FEA Analyzer

This analyzer enables the 2D transient FEA evaluation of synchronous reluctance (SynR) machines in JMAG.

8.1. Model Background

Synchronous reluctance (SynR) machines are electric machines capable of producing electromagnetic torque without the need for a rotor-mounted field source. Basic characteristics of the design and analysis of synchronous reluctance machines can be done by hand, as is shown in the paper here. Common ways of characterizing SynR machines include finding the following qualities of their design:

  1. Torque density

  2. Power density

  3. Efficiency

  4. Torque ripple

  • R. R. Moghaddam, F. Magnussen and C. Sadarangani, “A FEM1 investigation on the Synchronous Reluctance Machine rotor geometry with just one flux barrier as a guide toward the optimal barrier’s shape,” IEEE EUROCON 2009, St. Petersburg, Russia, 2009, pp. 663-670, doi: 10.1109/EURCON.2009.5167704.

This analyzer calculates the aforementioned parameters using JMAG’s transient solver. It has been set up such that the evaluation process is split into two distinct time-step sections. In the first section, the rotor current will reach steady state within a reasonable number of steps. Once the machine is at steady state, operation is evaluated by having small steps with respect to stator frequency. The following document will provide a description of the analyzer inputs and outputs:

8.2. Input from User

To use this analyzer, users must pass in a MachineDesign object. An instance of the MachineDesign class can be created by passing in machine and operating_point objects. The machine must be a SynR_Machine and the operating_point must be of type SynR_Machine_Oper_Pt. More information on both these classes is available in the SynR Design section under MACHINE DESIGNS. To initialize the SynR_JMAG_2D_FEA_Analyzer, users must also specify analyzer configuration parameters. One can control the version of JMAG desired for use in this analyzer using jmag_version. For example, the use of JMAG-Designer21.1 would require an input of 21.1.

The tables below provide the input expected by the MachineDesign class and the configuration input required to initialize the SynR_JMAG_2D_FEA_Analyzer.

MachineDesign Input

Arguments

Description

machine

object of type SynR_Machine describing a SynR design

operating_point

object of type SynR_Machine_Oper_Pt describing a SynR design operating point

SynR_JMAG_2D_FEA_Analyzer Initialization

Arguments

Description

configuration

object of type SynR_EM_Config describing time step, JMAG configurations, etc.

Example code initializing the machine design for the optimized SynR design provided in the example found in the SynR Design section of MACHINE DESIGNS is shown below. An identical file titled example_SynR_machine is stored in the SynR_eval folder within the mach_eval_examples folder in the examples folder of eMach.

import os
import sys

from mach_eval.machines.materials.electric_steels import (Arnon5)
from mach_eval.machines.materials.miscellaneous_materials import (
    Steel,
    Copper,
    Air,
)
from mach_eval.machines.SynR.SynR_machine import SynR_Machine
from mach_eval.machines.SynR.SynR_machine_oper_pt import SynR_Machine_Oper_Pt

SynR_dimensions = {
    'alpha_b': 135,
    'r_sh': 6,
    'r_ri': 6,
    'r_ro': 49,
    'r_f1': 0.1,
    'r_f2': 0.1,
    'r_f3': 0.1,
    'd_r1': 4,
    'd_r2': 8,
    'd_r3': 8,
    'w_b1': 4,
    'w_b2': 4,
    'w_b3': 4,
    'l_b1': 34.1,
    'l_b2': 24.75,
    'l_b3': 13.1,
    'l_b4': 13,
    'l_b5': 10,
    'l_b6': 7,
    'alpha_st': 25,
    'alpha_so': 12.5,
    'r_si': 50,
    'd_so': 5,
    'd_sp': 9,
    'd_st': 40,
    'd_sy': 36,
    'w_st': 12,
    'l_st': 100,
}

SynR_parameters = {
    'p': 2,
    'Q': 12,
    "name": "Example_SynR_Machine",
    'rated_speed': 1800,
    'rated_current': 20,
}

SynR_materials = {
    "air_mat": Air,
    "rotor_iron_mat": Arnon5,
    "stator_iron_mat": Arnon5,
    "coil_mat": Copper,
    "shaft_mat": Steel,
}

SynR_winding = {
    "no_of_layers": 2,
    "layer_phases": [ ['U', 'V', 'W', 'U', 'V', 'W', 'U', 'V', 'W', 'U', 'V', 'W'],
                        ['V', 'W', 'U', 'V', 'W', 'U', 'V', 'W', 'U', 'V', 'W', 'U'] ],
    "layer_polarity": [ ['+', '-', '+', '-', '+', '-', '+', '-', '+', '-', '+', '-'],
                        ['-', '+', '-', '+', '-', '+', '-', '+', '-', '+', '-', '+'] ],
    "pitch": 2,
    "Z_q": 20,
    "Kov": 1.8,
    "Kcu": 0.5,
    "phase_current_offset": 0,
}

Example_SynR_Machine = SynR_Machine(
    SynR_dimensions, SynR_parameters, SynR_materials, SynR_winding
)

################ DEFINE SynR operating point ################
Machine_Op_Pt = SynR_Machine_Oper_Pt(
    speed=1800,
    phi_0 = 0,
    ambient_temp=25,
    rotor_temp_rise=0,
)

To use this code, another file must be created and placed one level outside of the eMach folder in the repository in which it lies. The objective of this file is to call the example machine (in this case the example_SynR_machine.py that was just created in the SynR_eval folder) and create a machine design object.

import os
import sys
from time import time as clock_time

os.chdir(os.path.dirname(__file__))

from eMach.mach_eval import (MachineEvaluator, MachineDesign)
from eMach.examples.mach_eval_examples.SynR_eval.electromagnetic_step import electromagnetic_step
from eMach.examples.mach_eval_examples.SynR_eval.example_SynR_machine import Example_SynR_Machine, Machine_Op_Pt

############################ Create Evaluator ########################
SynR_evaluator = MachineEvaluator(
    [
        electromagnetic_step
    ]
)

design_variant = MachineDesign(Example_SynR_Machine, Machine_Op_Pt)

results = SynR_evaluator.evaluate(design_variant)

Example code defining the electromagnetic step is provided below. This code defines the analyzer problem class (input to the analyzer), initializes the analyzer class with an explanation of the required configurations, and calls the post-analyzer class. The SynR_EM_PostAnalyzer class is used to process the torque and power data (to calculate average and ripple values) and to print the results. This part can be modified by user to perform further processing (calculation of losses, efficiency, torque/power density, etc.). A copy of this file lies in the eMach\examples\mach_eval_examples\SynR_eval folder.

import os
import sys
import copy

from mach_eval import AnalysisStep, ProblemDefinition
from mach_eval.analyzers.electromagnetic.SynR import SynR_em_analyzer as SynR_em
from mach_eval.analyzers.electromagnetic.SynR.SynR_em_config import SynR_EM_Config
from examples.mach_eval_examples.SynR_eval.SynR_em_post_analyzer import SynR_EM_PostAnalyzer

############################ Define Electromagnetic Step ###########################
class SynR_EM_ProblemDefinition(ProblemDefinition):
    """Converts a State into a problem"""

    def __init__(self):
        pass

    def get_problem(state):

        problem = SynR_em.SynR_EM_Problem(
            state.design.machine, state.design.settings)
        return problem

# initialize em analyzer class with FEA configuration
configuration = SynR_EM_Config(
    no_of_rev = 1,
    no_of_steps = 72,

    mesh_size=3, # mm
    mesh_size_rotor=1.5, # mm
    airgap_mesh_radial_div=4,
    airgap_mesh_circum_div=720,
    mesh_air_region_scale=1.05,

    only_table_results=False,
    csv_results=("Torque;Force;FEMCoilFlux;LineCurrent;JouleLoss;TotalDisplacementAngle;"
                "JouleLoss_IronLoss;IronLoss_IronLoss;HysteresisLoss_IronLoss"),
    del_results_after_calc=False,
    run_folder=os.path.dirname(__file__) + "/run_data/",
    jmag_csv_folder=os.path.dirname(__file__) + "/run_data/jmag_csv/",

    max_nonlinear_iterations=50,
    multiple_cpus=True,
    num_cpus=4,
    jmag_scheduler=False,
    jmag_visible=True,
    scale_axial_length = True,
    jmag_version=None,
)

SynR_em_analysis = SynR_em.SynR_EM_Analyzer(configuration)

electromagnetic_step = AnalysisStep(SynR_EM_ProblemDefinition, SynR_em_analysis, SynR_EM_PostAnalyzer)

8.3. Output to User

The SynR_JMAG_2D_FEA_Analyzer returns a dictionary holding the results obtained from the transient analysis of the machine. The elements of this dictionary and their descriptions are provided below:

SynR_JMAG_2D_FEA_Analyzer Output

Output

Description

current

Data frame of stator and rotor currents in A vs time

torque

Data frame of torque in Nm vs time

force

Data frame of force in x and y axes in N vs time

iron_loss

Data frame of iron loss in W at different frequencies

hysteresis_loss

Data frame of hysterisis loss in W at different frequencies

eddy_current_loss

Data frame of eddy current loss in W at different frequencies

ohmic_loss

Data frame of ohmic loss in W vs time

Other parameters for post-processing:

no_of_steps_2nd_TSS

Number of revolutions for 2nd time step (at drive frequency)

no_of_rev_2nd_TSS

Number steps for 2nd time step section

scale_axial_length

Boolean determining whether to scale axial length

drive_freq

Drive frequency in Hz

stator_wdg_resistances

Array of stator winding resistances in Ohms: [total winding res., end winding res., res. along stack]

stator_slot_area_tha

Stator slot area in m^2

speed

Final rotor speed

As mentioned, the post analyzer is necessary to extract and compute the analyzer’s computations and to interpret the results. The post analyzer contains the following code and lies also in the eMach\examples\mach_eval_examples\SynR_eval folder. The code contained in the post analyzer, in this case to find torque and power quantities, can be seen here:

import copy
import numpy as np
import os
import sys

from mach_eval.analyzers.torque_data import (
    ProcessTorqueDataProblem,
    ProcessTorqueDataAnalyzer,
)

class SynR_EM_PostAnalyzer:
    def copper_loss(self):
        return 3 * (self.I ** 2) * (self.R_wdg)

    def get_next_state(results, in_state):
        state_out = copy.deepcopy(in_state)
        machine = state_out.design.machine
        op_pt = state_out.design.settings

        ############################ Extract required info ###########################
        no_of_steps = results["no_of_steps"]
        no_of_rev = results["no_of_rev"]
        number_of_total_steps = results["current"].shape[0]
        i1 = number_of_total_steps - no_of_steps
        i2 = - int(no_of_steps / no_of_rev * 0.25)
        omega_m = machine.omega_m
        m = 3
        drive_freq = results["drive_freq"]
        R_wdg = results["stator_wdg_resistances"][0]
        R_wdg_coil_ends = results["stator_wdg_resistances"][1]
        R_wdg_coil_sides = results["stator_wdg_resistances"][2]

        results["current"] = results["current"].iloc[i1:]
        results["torque"] = results["torque"].iloc[i1:]
        results["iron_loss"] = results["iron_loss"]
        results["hysteresis_loss"] = results["hysteresis_loss"]
        results["eddy_current_loss"] = results["eddy_current_loss"]

        ############################ calculating volumes ###########################
        machine = state_out.design.machine
        V_sh = np.pi*(machine.r_sh**2)*machine.l_st
        V_rfe = machine.l_st * (np.pi * (machine.r_ro ** 2 - machine.r_ri**2) - 2 * machine.p * (machine.w_b1 * (2 * machine.l_b1 + machine.l_b4) + machine.w_b2 * (2 * machine.l_b2 + machine.l_b5) + machine.w_b3 * (2 * machine.l_b3 + machine.l_b6)))

        ############################ Post-processing #################################
        rotor_mass = (
            V_rfe * 1e-9 * machine.rotor_iron_mat["core_material_density"]
            + V_sh * 1e-9 * machine.shaft_mat["shaft_material_density"]
        )
        rotor_volume = (V_rfe + V_sh) * 1e-9

        ############################ post processing ###########################
        # Torque
        torque_prob = ProcessTorqueDataProblem(results["torque"]["TorCon"])
        torque_analyzer = ProcessTorqueDataAnalyzer()
        torque_avg, torque_ripple = torque_analyzer.analyze(torque_prob)
        TRW = torque_avg / rotor_mass
        TRV = torque_avg / rotor_volume
        PRW = TRW * omega_m
        PRV = TRV * omega_m

        # Losses
        # From JMAG
        stator_iron_loss = results["iron_loss"]["StatorCore"][0]
        rotor_iron_loss = results["iron_loss"]["RotorCore"][0]
        stator_eddy_current_loss = results["eddy_current_loss"]["StatorCore"][0]
        rotor_eddy_current_loss = results["eddy_current_loss"]["RotorCore"][0]
        stator_hysteresis_loss= results["hysteresis_loss"]["StatorCore"][0]
        rotor_hysteresis_loss = results["hysteresis_loss"]["RotorCore"][0]
        stator_ohmic_loss = results["ohmic_loss"]["Coils"].iloc[i2:].mean()

        # Calculate stator winding ohmic losses
        I_hat = machine.rated_current * op_pt.current_ratio * np.sqrt(2)
        stator_calc_ohmic_loss = R_wdg * m / 2 * I_hat ** 2

        # Total losses, output power, and efficiency
        total_losses = (
            stator_iron_loss + rotor_iron_loss + stator_calc_ohmic_loss)
        P_out = torque_avg * omega_m
        efficiency = P_out / (P_out + total_losses)

        ############################ Output #################################
        post_processing = {}
        post_processing["torque_avg"] = torque_avg
        post_processing["torque_ripple"] = torque_ripple
        post_processing["TRW"] = TRW
        post_processing["TRV"] = TRV
        post_processing["PRW"] = PRW
        post_processing["PRV"] = PRV
        post_processing["l_st"] = machine.l_st
        post_processing["rotor_mass"] = rotor_mass
        post_processing["rotor_volume"] = rotor_volume
        post_processing["stator_iron_loss"] = stator_iron_loss
        post_processing["rotor_iron_loss"] = rotor_iron_loss
        post_processing["stator_eddy_current_loss"] = stator_eddy_current_loss
        post_processing["rotor_eddy_current_loss"] = rotor_eddy_current_loss
        post_processing["stator_hysteresis_loss"] = stator_hysteresis_loss
        post_processing["rotor_hysteresis_loss"] = rotor_hysteresis_loss
        post_processing["stator_ohmic_loss"] = stator_ohmic_loss
        post_processing["stator_calc_ohmic_loss"] = stator_calc_ohmic_loss
        post_processing["total_losses"] = total_losses
        post_processing["output_power"] = P_out
        post_processing["efficiency"] = efficiency

        state_out.conditions.em = post_processing

        print("\n************************ ELECTROMAGNETIC RESULTS ************************")
        #print("Torque = ", torque_avg, " Nm")
        print("Torque density = ", TRV, " Nm/m3",)
        print("Torque ripple = ", torque_ripple)
        #print("Power = ", P_out, " W")
        print("Power density = ", PRV, " W/m3",)
        print("Efficiency = ", efficiency * 100, " %")
        print("*************************************************************************\n")

        return state_out

All example SynR evaluation scripts, including the one used for this analyzer, can be found in eMach\examples\mach_eval_examples\SynR_eval, where the post-analyzer script uses FEA results and calculates machine performance metrics, including torque density, power density, efficiency, and torque ripple. This analyzer can be run by simply running the SynR_evaluator file in the aforementioned folder. This example should produce the following results:

SynR_JMAG_2D_FEA_Analyzer Results

Result

Value

Unit

Torque Density

11549

Nm/m3

Torque Ripple

0.2215

Power Density

2176964

W/m3

Efficiency

97.17

%