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:
Torque density
Power density
Efficiency
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.
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 |
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:
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:
Result |
Value |
Unit |
|---|---|---|
Torque Density |
11549 |
Nm/m3 |
Torque Ripple |
0.2215 |
|
Power Density |
2176964 |
W/m3 |
Efficiency |
97.17 |
% |